prism-mcp-server 2.1.2 β 2.3.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/README.md +56 -23
- package/dist/config.js +2 -3
- package/dist/dashboard/server.js +84 -0
- package/dist/dashboard/ui.js +182 -2
- package/dist/server.js +73 -13
- package/dist/storage/sqlite.js +119 -0
- package/dist/storage/supabase.js +93 -0
- package/dist/tools/index.js +2 -2
- package/dist/tools/sessionMemoryDefinitions.js +33 -0
- package/dist/tools/sessionMemoryHandlers.js +192 -1
- package/dist/utils/factMerger.js +104 -0
- package/dist/utils/healthCheck.js +307 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/prism-mcp-server)
|
|
4
4
|
[](https://registry.modelcontextprotocol.io)
|
|
5
|
-
[](https://glama.ai/mcp/servers
|
|
5
|
+
[](https://glama.ai/mcp/servers/dcostenco/BCBA)
|
|
6
6
|
[](https://smithery.ai/server/prism-mcp-server)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://www.typescriptlang.org/)
|
|
@@ -14,9 +14,26 @@
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
## What's New in v2.0
|
|
17
|
+
## What's New in v2.3.0 β AI Reasoning Engine π§
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
| Feature | Description |
|
|
20
|
+
|---|---|
|
|
21
|
+
| πΈοΈ **Neural Graph** | Interactive knowledge graph on the Mind Palace Dashboard β visualize how projects connect through shared keywords and categories using Vis.js force-directed layout. |
|
|
22
|
+
| π‘οΈ **Prompt Injection Shield** | Gemini-powered security scan in `session_health_check` β detects system override attempts, jailbreaks, and data exfiltration hidden in agent memory. Tuned to avoid false positives on normal dev commands. |
|
|
23
|
+
| 𧬠**Fact Merger** | Async LLM contradiction resolution on every handoff save β if old context says "Postgres" and new says "MySQL", Gemini silently merges the facts in the background. Zero latency impact (fire-and-forget). |
|
|
24
|
+
|
|
25
|
+
<details>
|
|
26
|
+
<summary><strong>What's in v2.2.0</strong></summary>
|
|
27
|
+
|
|
28
|
+
| Feature | Description |
|
|
29
|
+
|---|---|
|
|
30
|
+
| π©Ί **Brain Health Check** | `session_health_check` β like Unix `fsck` for your agent's memory. Detects missing embeddings, duplicate entries, orphaned handoffs, and stale rollups. Use `auto_fix: true` to repair automatically. |
|
|
31
|
+
| π **Mind Palace Health** | Brain health indicator on the Mind Palace Dashboard β see your memory integrity at a glance. |
|
|
32
|
+
|
|
33
|
+
</details>
|
|
34
|
+
|
|
35
|
+
<details>
|
|
36
|
+
<summary><strong>What's in v2.0 "Mind Palace"</strong></summary>
|
|
20
37
|
|
|
21
38
|
| Feature | Description |
|
|
22
39
|
|---|---|
|
|
@@ -29,6 +46,33 @@ Prism MCP has been completely rebuilt from the ground up to support **local-firs
|
|
|
29
46
|
| π **Code Mode Templates** | 8 pre-built QuickJS extraction templates for GitHub, Jira, OpenAPI, Slack, CSV, and DOM parsing β zero reasoning tokens. |
|
|
30
47
|
| π **Reality Drift Detection** | Prism captures Git state on save and warns if files changed outside the agent's view. |
|
|
31
48
|
|
|
49
|
+
</details>
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## How Prism Compares
|
|
54
|
+
|
|
55
|
+
| Feature | **Prism MCP** | [MCP Memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory) | [Mem0](https://github.com/mem0ai/mem0) | [Mnemory](https://github.com/fpytloun/mnemory) | [Basic Memory](https://github.com/basicmachines-co/basic-memory) |
|
|
56
|
+
|---|---|---|---|---|---|
|
|
57
|
+
| **Storage** | SQLite (local) + Supabase (cloud) | JSON file | Postgres + Qdrant (hosted or self-hosted) | Qdrant + S3/MinIO | Markdown files |
|
|
58
|
+
| **Zero Config** | β
`npx -y prism-mcp-server` | β
| β Requires Qdrant/Postgres | β
`uvx mnemory` | β
`pip install basic-memory` |
|
|
59
|
+
| **Semantic Search** | β
F32_BLOB vectors + FTS5 | β | β
pgvector | β
Qdrant vectors | β Text search only |
|
|
60
|
+
| **Knowledge Graph** | β
Neural Graph (Vis.js dashboard) | β
Entity/Relation model | β | β
Relationship graph | β
Markdown links |
|
|
61
|
+
| **Time Travel** | β
`memory_history` / `memory_checkout` | β | β | β | β |
|
|
62
|
+
| **Fact Merging** | β
Async Gemini (fire-and-forget) | β | β
Built-in | β
Contradiction resolution | β |
|
|
63
|
+
| **Security Scan** | β
Prompt injection detection | β | β | β
Anti-injection in fsck | β |
|
|
64
|
+
| **Health Check** | β
`session_health_check` (fsck) | β | β | β
3-phase fsck | β |
|
|
65
|
+
| **Visual Dashboard** | β
Mind Palace (localhost:3000) | β | β
Cloud dashboard | β
Management UI | β |
|
|
66
|
+
| **Multi-Agent Sync** | β
Real-time cross-client | β | β | β Per-user isolation | β |
|
|
67
|
+
| **Visual Memory** | β
Screenshot vault + auto-capture | β | β | β
Artifact store | β |
|
|
68
|
+
| **Auto-Compaction** | β
Gemini rollups | β | β | β | β |
|
|
69
|
+
| **Morning Briefing** | β
Gemini synthesis | β | β | β | β |
|
|
70
|
+
| **OCC (Concurrency)** | β
Version-based | β | β | β | β |
|
|
71
|
+
| **MCP Native** | β
stdio (Claude Desktop, Cursor) | β
stdio | β Python SDK / REST | β
HTTP + MCP | β
stdio |
|
|
72
|
+
| **Language** | TypeScript | TypeScript | Python | Python | Python |
|
|
73
|
+
|
|
74
|
+
> **When to choose Prism MCP:** You want MCP-native memory with zero infrastructure overhead, progressive context loading, and enterprise features (OCC, compaction, time travel, security scanning) that work directly in Claude Desktop β without running Qdrant, Postgres, or cloud services.
|
|
75
|
+
|
|
32
76
|
---
|
|
33
77
|
|
|
34
78
|
## Quick Start (Zero Config β Local Mode)
|
|
@@ -121,25 +165,6 @@ The dashboard auto-discovers all your projects and updates in real time.
|
|
|
121
165
|
|
|
122
166
|
---
|
|
123
167
|
|
|
124
|
-
## How Prism MCP Compares
|
|
125
|
-
|
|
126
|
-
| Capability | **Prism MCP** | **Mem0** | **Zep** | **Basic Memory** |
|
|
127
|
-
|---|---|---|---|---|
|
|
128
|
-
| **Architecture** | MCP-native (single npm package) | Standalone service + MCP adapter | Standalone service + API | MCP-native (local files) |
|
|
129
|
-
| **Storage** | SQLite (local) or Supabase (cloud) | Hybrid (vector + graph DBs) | PostgreSQL + Neo4j | Local markdown files |
|
|
130
|
-
| **Local-First** | β
Full SQLite mode, zero cloud | β Requires cloud/Docker | β Requires PostgreSQL | β
Local files |
|
|
131
|
-
| **Visual Dashboard** | β
Mind Palace UI at localhost:3000 | β No UI | β No UI | β No UI |
|
|
132
|
-
| **Time Travel** | β
Version history + checkout | β No versioning | β No versioning | β No versioning |
|
|
133
|
-
| **Multi-Agent Sync** | β
Telepathy (realtime IPC/CDC) | β Siloed | β Siloed | β Single user |
|
|
134
|
-
| **Auto-Capture** | β
HTML snapshots of dev server | β Text only | β Text only | β Text only |
|
|
135
|
-
| **Cold Start Fix** | β
MCP Prompts + Resources | β Requires tool call | β Requires tool call | β Requires tool call |
|
|
136
|
-
| **Progressive Loading** | β
quick / standard / deep | β All-or-nothing | β Fixed window | β All-or-nothing |
|
|
137
|
-
| **Semantic Search** | β
F32_BLOB vectors (local) or pgvector (cloud) | β
Qdrant/Chroma | β
Built-in | β None |
|
|
138
|
-
| **Concurrency Control** | β
OCC with version tracking | β Last write wins | β Last write wins | β Single user |
|
|
139
|
-
| **Setup Complexity** | Zero config (local mode) | Docker + API keys + vector DB | Docker + PostgreSQL + Neo4j | No setup needed |
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
168
|
## Integration Examples
|
|
144
169
|
|
|
145
170
|
Copy-paste configs for popular MCP clients. All configs use the `npx` method.
|
|
@@ -301,7 +326,7 @@ graph TB
|
|
|
301
326
|
| `knowledge_search` | Semantic search across accumulated knowledge |
|
|
302
327
|
| `knowledge_forget` | Prune outdated or incorrect memories (4 modes + dry_run) |
|
|
303
328
|
| `session_search_memory` | Vector similarity search across all sessions |
|
|
304
|
-
| `
|
|
329
|
+
| `session_compact_ledger` | Auto-compact old ledger entries via Gemini-powered summarization |
|
|
305
330
|
|
|
306
331
|
### v2.0 Advanced Memory Tools
|
|
307
332
|
|
|
@@ -312,6 +337,12 @@ graph TB
|
|
|
312
337
|
| `session_save_image` | Save a screenshot/image to the visual memory vault |
|
|
313
338
|
| `session_view_image` | Retrieve and display a saved image from the vault |
|
|
314
339
|
|
|
340
|
+
### v2.2 Brain Health Tools
|
|
341
|
+
|
|
342
|
+
| Tool | Purpose | Key Args | Returns |
|
|
343
|
+
|------|---------|----------|---------|
|
|
344
|
+
| `session_health_check` | Scan brain for integrity issues (`fsck`) | `auto_fix` (boolean) | Health report & auto-repairs |
|
|
345
|
+
|
|
315
346
|
### Code Mode Templates (v2.1)
|
|
316
347
|
|
|
317
348
|
Instead of writing custom JavaScript, pass a `template` name for instant extraction:
|
|
@@ -560,6 +591,8 @@ See [`vertex-ai/`](vertex-ai/) for setup and benchmarks.
|
|
|
560
591
|
β βββ googleAi.ts # Gemini SDK wrapper
|
|
561
592
|
β βββ executor.ts # QuickJS sandbox executor
|
|
562
593
|
β βββ autoCapture.ts # Dev server HTML snapshot utility
|
|
594
|
+
β βββ healthCheck.ts # Brain integrity engine (v2.2.0) + security scanner (v2.3.0)
|
|
595
|
+
β βββ factMerger.ts # Async LLM contradiction resolution (v2.3.0)
|
|
563
596
|
β βββ git.ts # Git state capture + drift detection
|
|
564
597
|
β βββ embeddingApi.ts # Embedding generation (Gemini)
|
|
565
598
|
β βββ keywordExtractor.ts # Zero-dependency NLP keyword extraction
|
package/dist/config.js
CHANGED
|
@@ -22,13 +22,12 @@
|
|
|
22
22
|
// multi-tenant Row Level Security (RLS) for production hosting.
|
|
23
23
|
export const SERVER_CONFIG = {
|
|
24
24
|
name: "prism-mcp",
|
|
25
|
-
version: "
|
|
25
|
+
version: "2.3.1",
|
|
26
26
|
};
|
|
27
27
|
// βββ Required: Brave Search API Key βββββββββββββββββββββββββββ
|
|
28
28
|
export const BRAVE_API_KEY = process.env.BRAVE_API_KEY;
|
|
29
29
|
if (!BRAVE_API_KEY) {
|
|
30
|
-
console.error("
|
|
31
|
-
process.exit(1);
|
|
30
|
+
console.error("Warning: BRAVE_API_KEY environment variable is missing. Search tools will return errors when called.");
|
|
32
31
|
}
|
|
33
32
|
// βββ Optional: Google Gemini API Key ββββββββββββββββββββββββββ
|
|
34
33
|
// Used by the gemini_research_paper_analysis tool.
|
package/dist/dashboard/server.js
CHANGED
|
@@ -68,6 +68,90 @@ export async function startDashboardServer() {
|
|
|
68
68
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
69
69
|
return res.end(JSON.stringify({ context, ledger, history }));
|
|
70
70
|
}
|
|
71
|
+
// βββ API: Brain Health Check (v2.2.0) βββ
|
|
72
|
+
if (url.pathname === "/api/health") {
|
|
73
|
+
try {
|
|
74
|
+
const { runHealthCheck } = await import("../utils/healthCheck.js");
|
|
75
|
+
const stats = await storage.getHealthStats(PRISM_USER_ID);
|
|
76
|
+
const report = runHealthCheck(stats);
|
|
77
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
78
|
+
return res.end(JSON.stringify(report));
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
console.error("[Dashboard] Health check error:", err);
|
|
82
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
83
|
+
return res.end(JSON.stringify({
|
|
84
|
+
status: "unknown",
|
|
85
|
+
summary: "Health check unavailable",
|
|
86
|
+
issues: [],
|
|
87
|
+
counts: { errors: 0, warnings: 0, infos: 0 },
|
|
88
|
+
totals: { activeEntries: 0, handoffs: 0, rollups: 0 },
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// βββ API: Knowledge Graph Data (v2.3.0) βββ
|
|
94
|
+
if (url.pathname === "/api/graph") {
|
|
95
|
+
// Fetch recent ledger entries to build the graph
|
|
96
|
+
// We look at the last 100 entries to keep the graph relevant but performant
|
|
97
|
+
const entries = await storage.getLedgerEntries({
|
|
98
|
+
limit: "100",
|
|
99
|
+
order: "created_at.desc",
|
|
100
|
+
select: "project,keywords",
|
|
101
|
+
});
|
|
102
|
+
// Deduplication sets for nodes and edges
|
|
103
|
+
const nodes = [];
|
|
104
|
+
const edges = [];
|
|
105
|
+
const nodeIds = new Set(); // track unique node IDs
|
|
106
|
+
const edgeIds = new Set(); // track unique edges
|
|
107
|
+
// Helper: add a node only if it doesn't already exist
|
|
108
|
+
const addNode = (id, group, label) => {
|
|
109
|
+
if (!nodeIds.has(id)) {
|
|
110
|
+
nodes.push({ id, label: label || id, group });
|
|
111
|
+
nodeIds.add(id);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// Helper: add an edge only if it doesn't already exist
|
|
115
|
+
const addEdge = (from, to) => {
|
|
116
|
+
const id = `${from}-${to}`; // deterministic edge ID
|
|
117
|
+
if (!edgeIds.has(id)) {
|
|
118
|
+
edges.push({ from, to });
|
|
119
|
+
edgeIds.add(id);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
// Transform relational data into graph nodes & edges
|
|
123
|
+
entries.forEach(row => {
|
|
124
|
+
if (!row.project)
|
|
125
|
+
return; // skip rows without project
|
|
126
|
+
// 1. Project node (hub β large purple dot)
|
|
127
|
+
addNode(row.project, "project");
|
|
128
|
+
// 2. Keyword nodes (spokes β small dots)
|
|
129
|
+
let keywords = [];
|
|
130
|
+
// Handle SQLite (JSON string) vs Supabase (native array)
|
|
131
|
+
if (Array.isArray(row.keywords)) {
|
|
132
|
+
keywords = row.keywords;
|
|
133
|
+
}
|
|
134
|
+
else if (typeof row.keywords === "string") {
|
|
135
|
+
try {
|
|
136
|
+
keywords = JSON.parse(row.keywords);
|
|
137
|
+
}
|
|
138
|
+
catch { /* skip malformed */ }
|
|
139
|
+
}
|
|
140
|
+
// Create nodes + edges for each keyword
|
|
141
|
+
keywords.forEach((kw) => {
|
|
142
|
+
if (kw.length < 3)
|
|
143
|
+
return; // skip noise like "a", "is"
|
|
144
|
+
// Handle categories (cat:debugging) vs raw keywords
|
|
145
|
+
const isCat = kw.startsWith("cat:");
|
|
146
|
+
const group = isCat ? "category" : "keyword";
|
|
147
|
+
const label = isCat ? kw.replace("cat:", "") : kw;
|
|
148
|
+
addNode(kw, group, label); // keyword/category node
|
|
149
|
+
addEdge(row.project, kw); // edge: project β keyword
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
153
|
+
return res.end(JSON.stringify({ nodes, edges }));
|
|
154
|
+
}
|
|
71
155
|
// βββ 404 βββ
|
|
72
156
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
73
157
|
res.end("Not found");
|
package/dist/dashboard/ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Mind Palace Dashboard β UI Renderer (v2.
|
|
2
|
+
* Mind Palace Dashboard β UI Renderer (v2.3.1)
|
|
3
3
|
*
|
|
4
4
|
* Pure CSS + Vanilla JS single-page dashboard.
|
|
5
5
|
* No build step, no Tailwind, no framework β served as a template literal.
|
|
@@ -22,6 +22,8 @@ export function renderDashboardHTML() {
|
|
|
22
22
|
<title>Prism MCP β Mind Palace</title>
|
|
23
23
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
24
24
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
25
|
+
<!-- Vis.js for Neural Graph (v2.3.0) -->
|
|
26
|
+
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
|
25
27
|
<style>
|
|
26
28
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
27
29
|
|
|
@@ -224,6 +226,50 @@ export function renderDashboardHTML() {
|
|
|
224
226
|
/* βββ Fade in animation βββ */
|
|
225
227
|
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
|
226
228
|
.fade-in { animation: fadeIn 0.4s ease-out forwards; }
|
|
229
|
+
|
|
230
|
+
/* βββ Brain Health Indicator (v2.2.0) βββ */
|
|
231
|
+
.health-status {
|
|
232
|
+
display: flex; align-items: center; gap: 0.75rem;
|
|
233
|
+
padding: 0.75rem 1rem; border-radius: var(--radius-sm);
|
|
234
|
+
background: rgba(15,23,42,0.6); margin-bottom: 1rem;
|
|
235
|
+
}
|
|
236
|
+
.health-dot {
|
|
237
|
+
width: 12px; height: 12px; border-radius: 50%;
|
|
238
|
+
flex-shrink: 0; position: relative;
|
|
239
|
+
}
|
|
240
|
+
.health-dot::after {
|
|
241
|
+
content: ''; position: absolute; inset: -3px;
|
|
242
|
+
border-radius: 50%; animation: healthPulse 2s ease-in-out infinite;
|
|
243
|
+
}
|
|
244
|
+
.health-dot.healthy { background: var(--accent-green); }
|
|
245
|
+
.health-dot.healthy::after { border: 2px solid rgba(16,185,129,0.3); }
|
|
246
|
+
.health-dot.degraded { background: var(--accent-amber); }
|
|
247
|
+
.health-dot.degraded::after { border: 2px solid rgba(245,158,11,0.3); }
|
|
248
|
+
.health-dot.unhealthy { background: var(--accent-rose); }
|
|
249
|
+
.health-dot.unhealthy::after { border: 2px solid rgba(244,63,94,0.3); }
|
|
250
|
+
.health-dot.unknown { background: var(--text-muted); }
|
|
251
|
+
.health-dot.unknown::after { border: 2px solid rgba(100,116,139,0.3); }
|
|
252
|
+
@keyframes healthPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
253
|
+
.health-label { font-size: 0.8rem; font-weight: 500; }
|
|
254
|
+
.health-summary { font-size: 0.75rem; color: var(--text-muted); }
|
|
255
|
+
.health-issues { font-size: 0.8rem; color: var(--text-secondary); margin-top: 0.5rem; }
|
|
256
|
+
.health-issues .issue-row {
|
|
257
|
+
padding: 0.3rem 0; display: flex; gap: 0.5rem; align-items: flex-start;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* βββ Neural Graph (v2.3.0) βββ */
|
|
261
|
+
#network-container {
|
|
262
|
+
width: 100%; height: 300px;
|
|
263
|
+
border-radius: var(--radius);
|
|
264
|
+
background: rgba(0,0,0,0.2);
|
|
265
|
+
border: 1px solid var(--border-glass);
|
|
266
|
+
}
|
|
267
|
+
.refresh-btn {
|
|
268
|
+
margin-left: auto; background: none; border: none;
|
|
269
|
+
color: var(--text-muted); cursor: pointer; font-size: 0.85rem;
|
|
270
|
+
transition: color 0.2s;
|
|
271
|
+
}
|
|
272
|
+
.refresh-btn:hover { color: var(--accent-purple); }
|
|
227
273
|
</style>
|
|
228
274
|
</head>
|
|
229
275
|
<body>
|
|
@@ -233,7 +279,7 @@ export function renderDashboardHTML() {
|
|
|
233
279
|
<div class="logo">
|
|
234
280
|
<span class="logo-icon">π§ </span>
|
|
235
281
|
Prism Mind Palace
|
|
236
|
-
<span class="version-badge">v2.
|
|
282
|
+
<span class="version-badge">v2.3.1</span>
|
|
237
283
|
</div>
|
|
238
284
|
<div class="selector">
|
|
239
285
|
<select id="projectSelect">
|
|
@@ -271,6 +317,19 @@ export function renderDashboardHTML() {
|
|
|
271
317
|
<div class="git-row"><span class="git-label">Key Context</span><span class="git-value" id="keyContext" style="font-family:var(--font-sans);max-width:200px;text-align:right">β</span></div>
|
|
272
318
|
</div>
|
|
273
319
|
|
|
320
|
+
<!-- Brain Health (v2.2.0) -->
|
|
321
|
+
<div class="card" id="healthCard" style="display:none">
|
|
322
|
+
<div class="card-title"><span class="dot" style="background:var(--accent-green)"></span> Brain Health π©Ί</div>
|
|
323
|
+
<div class="health-status">
|
|
324
|
+
<div class="health-dot unknown" id="healthDot"></div>
|
|
325
|
+
<div>
|
|
326
|
+
<div class="health-label" id="healthLabel">Scanning...</div>
|
|
327
|
+
<div class="health-summary" id="healthSummary"></div>
|
|
328
|
+
</div>
|
|
329
|
+
</div>
|
|
330
|
+
<div class="health-issues" id="healthIssues"></div>
|
|
331
|
+
</div>
|
|
332
|
+
|
|
274
333
|
<!-- Morning Briefing -->
|
|
275
334
|
<div class="card" id="briefingCard" style="display:none">
|
|
276
335
|
<div class="card-title"><span class="dot" style="background:var(--accent-amber)"></span> Morning Briefing π
</div>
|
|
@@ -286,6 +345,17 @@ export function renderDashboardHTML() {
|
|
|
286
345
|
|
|
287
346
|
<!-- Right Column -->
|
|
288
347
|
<div class="grid" style="align-content: start;">
|
|
348
|
+
|
|
349
|
+
<!-- Neural Graph (v2.3.0) -->
|
|
350
|
+
<div class="card">
|
|
351
|
+
<div class="card-title">
|
|
352
|
+
<span class="dot" style="background:var(--accent-blue)"></span>
|
|
353
|
+
Neural Graph πΈοΈ
|
|
354
|
+
<button onclick="loadGraph()" class="refresh-btn">β»</button>
|
|
355
|
+
</div>
|
|
356
|
+
<div id="network-container">Loading nodes...</div>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
289
359
|
<!-- Time Travel -->
|
|
290
360
|
<div class="card">
|
|
291
361
|
<div class="card-title"><span class="dot" style="background:var(--accent-purple)"></span> Time Travel History π°οΈ</div>
|
|
@@ -413,6 +483,49 @@ export function renderDashboardHTML() {
|
|
|
413
483
|
ledgerEl.innerHTML = '<div style="color:var(--text-muted);font-size:0.85rem;padding:1rem;text-align:center">No ledger entries yet.</div>';
|
|
414
484
|
}
|
|
415
485
|
|
|
486
|
+
// βββ Brain Health (v2.2.0) βββ
|
|
487
|
+
try {
|
|
488
|
+
var healthRes = await fetch('/api/health');
|
|
489
|
+
var healthData = await healthRes.json();
|
|
490
|
+
var healthCard = document.getElementById('healthCard');
|
|
491
|
+
var healthDot = document.getElementById('healthDot');
|
|
492
|
+
var healthLabel = document.getElementById('healthLabel');
|
|
493
|
+
var healthSummary = document.getElementById('healthSummary');
|
|
494
|
+
var healthIssues = document.getElementById('healthIssues');
|
|
495
|
+
|
|
496
|
+
// Set the dot color based on status
|
|
497
|
+
healthDot.className = 'health-dot ' + (healthData.status || 'unknown');
|
|
498
|
+
|
|
499
|
+
// Map status to emoji + label
|
|
500
|
+
var statusMap = { healthy: 'β
Healthy', degraded: 'β οΈ Degraded', unhealthy: 'π΄ Unhealthy' };
|
|
501
|
+
healthLabel.textContent = statusMap[healthData.status] || 'β Unknown';
|
|
502
|
+
|
|
503
|
+
// Stats summary line
|
|
504
|
+
var t = healthData.totals || {};
|
|
505
|
+
healthSummary.textContent = (t.activeEntries || 0) + ' entries Β· ' +
|
|
506
|
+
(t.handoffs || 0) + ' handoffs Β· ' +
|
|
507
|
+
(t.rollups || 0) + ' rollups';
|
|
508
|
+
|
|
509
|
+
// Issue rows
|
|
510
|
+
var issues = healthData.issues || [];
|
|
511
|
+
if (issues.length > 0) {
|
|
512
|
+
var sevIcons = { error: 'π΄', warning: 'π‘', info: 'π΅' };
|
|
513
|
+
healthIssues.innerHTML = issues.map(function(i) {
|
|
514
|
+
return '<div class="issue-row">' +
|
|
515
|
+
'<span>' + (sevIcons[i.severity] || 'β') + '</span>' +
|
|
516
|
+
'<span>' + escapeHtml(i.message) + '</span>' +
|
|
517
|
+
'</div>';
|
|
518
|
+
}).join('');
|
|
519
|
+
} else {
|
|
520
|
+
healthIssues.innerHTML = '<div style="color:var(--accent-green);font-size:0.8rem">π No issues found</div>';
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
healthCard.style.display = 'block';
|
|
524
|
+
} catch(he) {
|
|
525
|
+
// Health check not available β silently skip
|
|
526
|
+
console.warn('Health check unavailable:', he);
|
|
527
|
+
}
|
|
528
|
+
|
|
416
529
|
document.getElementById('content').className = 'grid grid-main fade-in';
|
|
417
530
|
document.getElementById('content').style.display = 'grid';
|
|
418
531
|
} catch(e) {
|
|
@@ -438,6 +551,73 @@ export function renderDashboardHTML() {
|
|
|
438
551
|
|
|
439
552
|
// Allow Enter key in select to trigger load
|
|
440
553
|
document.getElementById('projectSelect').addEventListener('change', loadProject);
|
|
554
|
+
|
|
555
|
+
// βββ Neural Graph (v2.3.0) βββ
|
|
556
|
+
// Renders a force-directed graph of projects β keywords β categories
|
|
557
|
+
async function loadGraph() {
|
|
558
|
+
var container = document.getElementById('network-container');
|
|
559
|
+
if (!container) return;
|
|
560
|
+
|
|
561
|
+
try {
|
|
562
|
+
var res = await fetch('/api/graph');
|
|
563
|
+
var data = await res.json();
|
|
564
|
+
|
|
565
|
+
// Empty state β no ledger entries yet
|
|
566
|
+
if (data.nodes.length === 0) {
|
|
567
|
+
container.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:0.85rem">No knowledge associations found yet.</div>';
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Vis.js dark-theme config matching the glassmorphism palette
|
|
572
|
+
var options = {
|
|
573
|
+
nodes: {
|
|
574
|
+
shape: 'dot', // all nodes are circles
|
|
575
|
+
borderWidth: 0, // no borders for clean look
|
|
576
|
+
font: { color: '#94a3b8', face: 'Inter', size: 12 }
|
|
577
|
+
},
|
|
578
|
+
edges: {
|
|
579
|
+
width: 1, // thin edges for subtlety
|
|
580
|
+
color: { color: 'rgba(139,92,246,0.15)', highlight: '#8b5cf6' },
|
|
581
|
+
smooth: { type: 'continuous' } // smooth curves
|
|
582
|
+
},
|
|
583
|
+
groups: {
|
|
584
|
+
project: { // Hub nodes β large purple
|
|
585
|
+
color: { background: '#8b5cf6', border: '#7c3aed' },
|
|
586
|
+
size: 20,
|
|
587
|
+
font: { size: 14, color: '#f1f5f9', face: 'Inter' }
|
|
588
|
+
},
|
|
589
|
+
category: { // Category nodes β cyan diamonds
|
|
590
|
+
color: { background: '#06b6d4', border: '#0891b2' },
|
|
591
|
+
size: 10,
|
|
592
|
+
shape: 'diamond'
|
|
593
|
+
},
|
|
594
|
+
keyword: { // Keyword nodes β small dark dots
|
|
595
|
+
color: { background: '#1e293b', border: '#334155' },
|
|
596
|
+
size: 6,
|
|
597
|
+
font: { size: 10, color: '#64748b' }
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
physics: {
|
|
601
|
+
stabilization: false, // animate on load for visual pop
|
|
602
|
+
barnesHut: {
|
|
603
|
+
gravitationalConstant: -3000, // spread nodes apart
|
|
604
|
+
springConstant: 0.04, // gentle spring force
|
|
605
|
+
springLength: 80 // default edge length
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
interaction: { hover: true } // highlight on hover
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
// Create the network visualization
|
|
612
|
+
new vis.Network(container, data, options);
|
|
613
|
+
} catch (e) {
|
|
614
|
+
console.error('Graph error', e);
|
|
615
|
+
container.innerHTML = '<div style="padding:1rem;color:var(--accent-rose)">Graph failed to load</div>';
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Initialize the graph on page load
|
|
620
|
+
loadGraph();
|
|
441
621
|
</script>
|
|
442
622
|
</body>
|
|
443
623
|
</html>`;
|
package/dist/server.js
CHANGED
|
@@ -72,17 +72,21 @@ import { WEB_SEARCH_TOOL, BRAVE_WEB_SEARCH_CODE_MODE_TOOL, LOCAL_SEARCH_TOOL, BR
|
|
|
72
72
|
// Session memory tools β only used if Supabase is configured
|
|
73
73
|
import { SESSION_SAVE_LEDGER_TOOL, SESSION_SAVE_HANDOFF_TOOL, SESSION_LOAD_CONTEXT_TOOL, KNOWLEDGE_SEARCH_TOOL, KNOWLEDGE_FORGET_TOOL,
|
|
74
74
|
// βββ v0.4.0: New tool definitions (Enhancements #2 and #4) βββ
|
|
75
|
-
SESSION_COMPACT_LEDGER_TOOL, SESSION_SEARCH_MEMORY_TOOL,
|
|
75
|
+
SESSION_COMPACT_LEDGER_TOOL, SESSION_SEARCH_MEMORY_TOOL,
|
|
76
76
|
// βββ v2.0: Time Travel tool definitions βββ
|
|
77
77
|
MEMORY_HISTORY_TOOL, MEMORY_CHECKOUT_TOOL,
|
|
78
78
|
// βββ v2.0: Visual Memory tool definitions βββ
|
|
79
|
-
SESSION_SAVE_IMAGE_TOOL, SESSION_VIEW_IMAGE_TOOL,
|
|
79
|
+
SESSION_SAVE_IMAGE_TOOL, SESSION_VIEW_IMAGE_TOOL,
|
|
80
|
+
// βββ v2.2.0: Health Check tool definition βββ
|
|
81
|
+
SESSION_HEALTH_CHECK_TOOL, sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler,
|
|
80
82
|
// βββ v0.4.0: New tool handlers βββ
|
|
81
|
-
compactLedgerHandler, sessionSearchMemoryHandler,
|
|
83
|
+
compactLedgerHandler, sessionSearchMemoryHandler,
|
|
82
84
|
// βββ v2.0: Time Travel handlers βββ
|
|
83
85
|
memoryHistoryHandler, memoryCheckoutHandler,
|
|
84
86
|
// βββ v2.0: Visual Memory handlers βββ
|
|
85
|
-
sessionSaveImageHandler, sessionViewImageHandler,
|
|
87
|
+
sessionSaveImageHandler, sessionViewImageHandler,
|
|
88
|
+
// βββ v2.2.0: Health Check handler βββ
|
|
89
|
+
sessionHealthCheckHandler, } from "./tools/index.js";
|
|
86
90
|
// βββ Dynamic Tool Registration βββββββββββββββββββββββββββββββββββ
|
|
87
91
|
// Base tools: always available regardless of configuration
|
|
88
92
|
const BASE_TOOLS = [
|
|
@@ -106,12 +110,13 @@ const SESSION_MEMORY_TOOLS = [
|
|
|
106
110
|
KNOWLEDGE_FORGET_TOOL, // knowledge_forget β prune bad/old memories
|
|
107
111
|
SESSION_COMPACT_LEDGER_TOOL, // session_compact_ledger β auto-compact old ledger entries (v0.4.0)
|
|
108
112
|
SESSION_SEARCH_MEMORY_TOOL, // session_search_memory β semantic search via embeddings (v0.4.0)
|
|
109
|
-
SESSION_BACKFILL_EMBEDDINGS_TOOL, // session_backfill_embeddings β repair missing embeddings
|
|
110
113
|
MEMORY_HISTORY_TOOL, // memory_history β view version timeline (v2.0)
|
|
111
114
|
MEMORY_CHECKOUT_TOOL, // memory_checkout β revert to past version (v2.0)
|
|
112
115
|
// βββ v2.0: Visual Memory tools βββ
|
|
113
116
|
SESSION_SAVE_IMAGE_TOOL, // session_save_image β save image to media vault (v2.0)
|
|
114
117
|
SESSION_VIEW_IMAGE_TOOL, // session_view_image β retrieve image from vault (v2.0)
|
|
118
|
+
// βββ v2.2.0: Health Check tool βββ
|
|
119
|
+
SESSION_HEALTH_CHECK_TOOL, // session_health_check β brain integrity checker (v2.2.0)
|
|
115
120
|
];
|
|
116
121
|
// Combine: if session memory is enabled, add those tools too
|
|
117
122
|
const ALL_TOOLS = [
|
|
@@ -477,10 +482,6 @@ export function createServer() {
|
|
|
477
482
|
if (!SESSION_MEMORY_ENABLED)
|
|
478
483
|
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
479
484
|
return await sessionSearchMemoryHandler(args);
|
|
480
|
-
case "session_backfill_embeddings":
|
|
481
|
-
if (!SESSION_MEMORY_ENABLED)
|
|
482
|
-
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
483
|
-
return await backfillEmbeddingsHandler(args);
|
|
484
485
|
// βββ v2.0: Time Travel Tools βββ
|
|
485
486
|
case "memory_history":
|
|
486
487
|
if (!SESSION_MEMORY_ENABLED)
|
|
@@ -499,6 +500,11 @@ export function createServer() {
|
|
|
499
500
|
if (!SESSION_MEMORY_ENABLED)
|
|
500
501
|
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
501
502
|
return await sessionViewImageHandler(args);
|
|
503
|
+
// βββ v2.2.0: Health Check Tool βββ
|
|
504
|
+
case "session_health_check":
|
|
505
|
+
if (!SESSION_MEMORY_ENABLED)
|
|
506
|
+
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
507
|
+
return await sessionHealthCheckHandler(args);
|
|
502
508
|
default:
|
|
503
509
|
return {
|
|
504
510
|
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
@@ -521,11 +527,65 @@ export function createServer() {
|
|
|
521
527
|
});
|
|
522
528
|
return server;
|
|
523
529
|
}
|
|
524
|
-
// βββ Smithery Sandbox Export
|
|
525
|
-
// Smithery
|
|
526
|
-
// without requiring real credentials
|
|
530
|
+
// βββ Smithery/Glama Sandbox Export βββββββββββββββββββββββββββββββ
|
|
531
|
+
// Scanners (Smithery, Glama) use this to enumerate capabilities
|
|
532
|
+
// (tools, prompts, resources) without requiring real credentials.
|
|
533
|
+
// Unlike createServer(), this always exposes ALL capabilities
|
|
534
|
+
// regardless of whether SESSION_MEMORY_ENABLED is true.
|
|
527
535
|
export function createSandboxServer() {
|
|
528
|
-
|
|
536
|
+
const server = new Server({
|
|
537
|
+
name: SERVER_CONFIG.name,
|
|
538
|
+
version: SERVER_CONFIG.version,
|
|
539
|
+
}, {
|
|
540
|
+
capabilities: {
|
|
541
|
+
tools: {
|
|
542
|
+
tools: [...BASE_TOOLS, ...SESSION_MEMORY_TOOLS],
|
|
543
|
+
},
|
|
544
|
+
prompts: {},
|
|
545
|
+
resources: { subscribe: true },
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
// Register all tool listings unconditionally
|
|
549
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
550
|
+
tools: [...BASE_TOOLS, ...SESSION_MEMORY_TOOLS],
|
|
551
|
+
}));
|
|
552
|
+
// Register prompts listing so scanners see resume_session
|
|
553
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
554
|
+
prompts: [{
|
|
555
|
+
name: "resume_session",
|
|
556
|
+
description: "Load previous session context for a project. " +
|
|
557
|
+
"Automatically fetches handoff state and injects it before " +
|
|
558
|
+
"the LLM starts thinking β no tool call needed. " +
|
|
559
|
+
"Includes version tracking for concurrency control.",
|
|
560
|
+
arguments: [
|
|
561
|
+
{
|
|
562
|
+
name: "project",
|
|
563
|
+
description: "Project identifier to resume (e.g., 'prism-mcp')",
|
|
564
|
+
required: true,
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
name: "level",
|
|
568
|
+
description: "Context depth: 'quick' (~50 tokens), " +
|
|
569
|
+
"'standard' (~200 tokens, recommended), " +
|
|
570
|
+
"'deep' (full history, ~1000+ tokens)",
|
|
571
|
+
required: false,
|
|
572
|
+
},
|
|
573
|
+
],
|
|
574
|
+
}],
|
|
575
|
+
}));
|
|
576
|
+
// Register resource templates so scanners see memory://{project}/handoff
|
|
577
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
|
|
578
|
+
resourceTemplates: [{
|
|
579
|
+
uriTemplate: "memory://{project}/handoff",
|
|
580
|
+
name: "Session Handoff State",
|
|
581
|
+
description: "Current handoff state for a project β includes " +
|
|
582
|
+
"last summary, pending TODOs, active decisions, keywords, " +
|
|
583
|
+
"and version number for concurrency control. " +
|
|
584
|
+
"Attach this to inject session context without a tool call.",
|
|
585
|
+
mimeType: "application/json",
|
|
586
|
+
}],
|
|
587
|
+
}));
|
|
588
|
+
return server;
|
|
529
589
|
}
|
|
530
590
|
// βββ Server Startup βββββββββββββββββββββββββββββββββββββββββββββ
|
|
531
591
|
/**
|