prism-mcp-server 2.5.2 → 3.0.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 +195 -5
- package/dist/config.js +8 -0
- package/dist/dashboard/server.js +134 -3
- package/dist/dashboard/ui.js +612 -2
- package/dist/server.js +67 -13
- package/dist/storage/configStorage.js +73 -0
- package/dist/storage/index.js +8 -5
- package/dist/storage/sqlite.js +249 -20
- package/dist/storage/supabase.js +96 -106
- package/dist/tools/agentRegistryDefinitions.js +104 -0
- package/dist/tools/agentRegistryHandlers.js +119 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/sessionMemoryDefinitions.js +12 -0
- package/dist/tools/sessionMemoryHandlers.js +35 -5
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
## Table of Contents
|
|
16
16
|
|
|
17
|
-
- [What's New (
|
|
17
|
+
- [What's New (v3.0.1)](#whats-new-in-v301---agent-identity--brain-clean-up-)
|
|
18
18
|
- [How Prism Compares](#how-prism-compares)
|
|
19
19
|
- [Quick Start](#quick-start-zero-config--local-mode)
|
|
20
20
|
- [Mind Palace Dashboard](#-the-mind-palace-dashboard)
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
- [Use Cases](#use-cases)
|
|
23
23
|
- [Architecture](#architecture)
|
|
24
24
|
- [Tool Reference](#tool-reference)
|
|
25
|
+
- [Agent Hivemind — Role Usage](#agent-hivemind--role-usage)
|
|
25
26
|
- [LangChain / LangGraph Integration](#langchain--langgraph-integration)
|
|
26
27
|
- [Environment Variables](#environment-variables)
|
|
28
|
+
- [Boot Settings (Restart Required)](#-boot-settings-restart-required)
|
|
27
29
|
- [Progressive Context Loading](#progressive-context-loading)
|
|
28
30
|
- [Time Travel](#time-travel-version-history)
|
|
29
31
|
- [Agent Telepathy](#agent-telepathy-multi-client-sync)
|
|
@@ -37,7 +39,33 @@
|
|
|
37
39
|
|
|
38
40
|
---
|
|
39
41
|
|
|
40
|
-
## What's New in
|
|
42
|
+
## What's New in v3.0.1 — Agent Identity & Brain Clean-up 🧹
|
|
43
|
+
|
|
44
|
+
| Feature | Description |
|
|
45
|
+
|---|---|
|
|
46
|
+
| 🧹 **Brain Health Clean-up** | New **Fix Issues** button in the Mind Palace Dashboard's Brain Health card — detects orphaned handoffs, missing embeddings, and stale rollups, then cleans them up in one click without needing the MCP tool. |
|
|
47
|
+
| 👤 **Agent Identity Settings** | Dashboard Settings → Agent Identity panel lets you set a **Default Role** (`dev`, `qa`, `pm`…) and **Agent Name** (e.g. `Dmitri`). Both values auto-apply as fallbacks in all memory and Hivemind tools — no need to pass them per call. |
|
|
48
|
+
| 📜 **Role-Scoped Skills** | Each agent role can have its own persistent skill/rules document stored in the dashboard (⚙️ Settings → Skills). It is automatically injected into every `session_load_context` response so the agent boots with its rules pre-loaded. |
|
|
49
|
+
| 🔤 **Resource Formatting Fix** | `memory://{project}/handoff` resources now render as formatted plain text (Last Summary, TODOs, Keywords) instead of a raw JSON blob — readable in Claude Desktop's paperclip attach panel. |
|
|
50
|
+
|
|
51
|
+
<details>
|
|
52
|
+
<summary><strong>What's in v3.0.0 — Agent Hivemind 🐝</strong></summary>
|
|
53
|
+
|
|
54
|
+
| Feature | Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| 🐝 **Role-Scoped Memory** | Optional `role` parameter on ledger, handoff, and context loading — each agent role (dev, qa, pm, lead, security, ux) gets its own isolated memory lane within a project. Defaults to `'global'` for full backward compatibility. |
|
|
57
|
+
| 👥 **Agent Registry** | New `agent_register`, `agent_heartbeat`, `agent_list_team` tools — agents announce their presence, pulse their status, and discover who else is working on the team. Stale agents are auto-pruned after 30 minutes. |
|
|
58
|
+
| 🎯 **Team Roster Injection** | When loading context with a role, Prism automatically injects a "Team Roster" showing active teammates, their roles, current tasks, and last heartbeat — true multi-agent awareness without extra tool calls. |
|
|
59
|
+
| ⚙️ **Dashboard Settings** | New Settings modal with runtime toggles (auto-capture, theme, context depth) backed by a persistent `system_settings` key-value store. Environment variables override DB settings for safety. |
|
|
60
|
+
| 📡 **Hivemind Radar** | New dashboard widget showing active agents, their roles (with icons), current tasks, and heartbeat timestamps — a real-time team coordination dashboard. |
|
|
61
|
+
| 🔒 **Conditional Tool Registration** | `PRISM_ENABLE_HIVEMIND` env var gates Hivemind tools — users who don't need multi-agent features keep the same lean tool count as v2.x. |
|
|
62
|
+
| ✅ **Test Suite** | 58 tests across 4 suites (storage, tools, dashboard, load) with Vitest — includes concurrent write stress tests, role isolation verification, and 0.2ms/write performance benchmarks. |
|
|
63
|
+
|
|
64
|
+
</details>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<details>
|
|
68
|
+
<summary><strong>What's in v2.5.0 — Enterprise Memory 🏗️</strong></summary>
|
|
41
69
|
|
|
42
70
|
| Feature | Description |
|
|
43
71
|
|---|---|
|
|
@@ -46,6 +74,8 @@
|
|
|
46
74
|
| 🔗 **LangChain Integration (Phase 3)** | `PrismMemoryRetriever` and `PrismKnowledgeRetriever` — async-first `BaseRetriever` subclasses that wrap Prism MCP's traced search endpoints. Trace metadata flows automatically into `Document.metadata["trace"]` for LangSmith visibility. |
|
|
47
75
|
| 🧩 **LangGraph Research Agent** | Full example in `examples/langgraph-agent/` — a 5-node agentic research loop with MCP bridge, persistent memory, and `EnsembleRetriever` hybrid search. |
|
|
48
76
|
|
|
77
|
+
</details>
|
|
78
|
+
|
|
49
79
|
<details>
|
|
50
80
|
<summary><strong>What's in v2.5.1 — Version Sync & Embedding Safety</strong></summary>
|
|
51
81
|
|
|
@@ -86,7 +116,7 @@
|
|
|
86
116
|
| Feature | Description |
|
|
87
117
|
|---|---|
|
|
88
118
|
| 🩺 **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. |
|
|
89
|
-
| 📊 **Mind Palace Health** | Brain health indicator on the Mind Palace Dashboard — see your memory integrity at a glance. |
|
|
119
|
+
| 📊 **Mind Palace Health** | Brain health indicator on the Mind Palace Dashboard — see your memory integrity at a glance. **🧹 Fix Issues** button auto-deletes orphaned handoffs in one click. |
|
|
90
120
|
|
|
91
121
|
</details>
|
|
92
122
|
|
|
@@ -221,11 +251,15 @@ Open **`http://localhost:3000`** in your browser to see exactly what your AI age
|
|
|
221
251
|

|
|
222
252
|
|
|
223
253
|
- **Current State & TODOs** — See the exact context injected into the LLM's prompt
|
|
254
|
+
- **Agent Identity Chip** — Header shows your active role + name (e.g. `🛠️ dev · Antigravity`); click to open Settings
|
|
255
|
+
- **Brain Health 🩺** — Memory integrity status at a glance; **🧹 Fix Issues** button auto-cleans orphaned handoffs in one click
|
|
224
256
|
- **Git Drift Detection** — Alerts you if you've modified code outside the agent's view
|
|
225
257
|
- **Morning Briefing** — AI-synthesized action plan from your last sessions
|
|
226
258
|
- **Time Travel Timeline** — Browse historical handoff states and revert any version
|
|
227
259
|
- **Visual Memory Vault** — Browse UI screenshots and auto-captured HTML states
|
|
228
260
|
- **Session Ledger** — Full audit trail of every decision your agent has made
|
|
261
|
+
- **Neural Graph** — Force-directed visualization of project ↔ keyword associations
|
|
262
|
+
- **Hivemind Radar** — Real-time active agent roster with role, task, and heartbeat
|
|
229
263
|
|
|
230
264
|
The dashboard auto-discovers all your projects and updates in real time.
|
|
231
265
|
|
|
@@ -447,7 +481,15 @@ graph TB
|
|
|
447
481
|
|
|
448
482
|
| Tool | Purpose | Key Args | Returns |
|
|
449
483
|
|------|---------|----------|---------|
|
|
450
|
-
| `session_health_check` | Scan brain for integrity issues (`fsck`) | `auto_fix` (boolean) | Health report & auto-repairs |
|
|
484
|
+
| `session_health_check` | Scan brain for integrity issues (`fsck`) | `project`, `auto_fix` (boolean) | Health report & auto-repairs |
|
|
485
|
+
|
|
486
|
+
The **Mind Palace Dashboard** also shows a live **Brain Health 🩺** card for every project:
|
|
487
|
+
|
|
488
|
+
- **Status indicator** — `✅ Healthy` or `⚠️ Issues detected` with entry/handoff/rollup counts
|
|
489
|
+
- **🧹 Fix Issues button** — appears automatically when issues are detected; click to clean up orphaned handoffs and stale rollups in one click, no MCP tool call required
|
|
490
|
+
- **No issues found** — shown in green when memory integrity is confirmed
|
|
491
|
+
|
|
492
|
+
The tool and dashboard button both call the same repair logic — the dashboard button is simply a zero-friction shortcut for common maintenance.
|
|
451
493
|
|
|
452
494
|
### v2.5 Enterprise Memory Tools
|
|
453
495
|
|
|
@@ -476,6 +518,110 @@ Instead of writing custom JavaScript, pass a `template` name for instant extract
|
|
|
476
518
|
|
|
477
519
|
---
|
|
478
520
|
|
|
521
|
+
## Agent Hivemind — Role Usage
|
|
522
|
+
|
|
523
|
+
Role-scoped memory lets multiple agents work on the same project without stepping on each other's memory. Each role gets its own isolated memory lane. Defaults to `global` for full backward compatibility.
|
|
524
|
+
|
|
525
|
+
### Available Roles
|
|
526
|
+
|
|
527
|
+
| Role | Use for |
|
|
528
|
+
|------|---------|
|
|
529
|
+
| `dev` | Development agent |
|
|
530
|
+
| `qa` | Testing / QA agent |
|
|
531
|
+
| `pm` | Product management |
|
|
532
|
+
| `lead` | Tech lead / orchestrator |
|
|
533
|
+
| `security` | Security review |
|
|
534
|
+
| `ux` | Design / UX |
|
|
535
|
+
| `global` | Default — shared, no isolation |
|
|
536
|
+
|
|
537
|
+
Custom role strings are also supported (e.g. `"docs"`, `"ml"`).
|
|
538
|
+
|
|
539
|
+
### Using Roles with Memory Tools
|
|
540
|
+
|
|
541
|
+
Just add `"role"` to any of the core memory tools:
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
// Save a ledger entry as the "dev" agent
|
|
545
|
+
{ "name": "session_save_ledger", "arguments": {
|
|
546
|
+
"project": "my-app",
|
|
547
|
+
"role": "dev",
|
|
548
|
+
"conversation_id": "abc123",
|
|
549
|
+
"summary": "Fixed the auth race condition"
|
|
550
|
+
}}
|
|
551
|
+
|
|
552
|
+
// Load context scoped to your role
|
|
553
|
+
// Also injects a Team Roster showing active teammates
|
|
554
|
+
{ "name": "session_load_context", "arguments": {
|
|
555
|
+
"project": "my-app",
|
|
556
|
+
"role": "dev",
|
|
557
|
+
"level": "standard"
|
|
558
|
+
}}
|
|
559
|
+
|
|
560
|
+
// Save handoff as the "qa" agent
|
|
561
|
+
{ "name": "session_save_handoff", "arguments": {
|
|
562
|
+
"project": "my-app",
|
|
563
|
+
"role": "qa",
|
|
564
|
+
"last_summary": "Ran regression suite — 2 failures in auth module"
|
|
565
|
+
}}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Hivemind Coordination Tools
|
|
569
|
+
|
|
570
|
+
> **Requires:** `PRISM_ENABLE_HIVEMIND=true` (Boot Setting — restart required)
|
|
571
|
+
|
|
572
|
+
```json
|
|
573
|
+
// Announce yourself to the team at session start
|
|
574
|
+
{ "name": "agent_register", "arguments": {
|
|
575
|
+
"project": "my-app",
|
|
576
|
+
"role": "dev",
|
|
577
|
+
"agent_name": "Dev Agent #1",
|
|
578
|
+
"current_task": "Refactoring auth module"
|
|
579
|
+
}}
|
|
580
|
+
|
|
581
|
+
// Pulse every ~5 min to stay visible (agents pruned after 30 min)
|
|
582
|
+
{ "name": "agent_heartbeat", "arguments": {
|
|
583
|
+
"project": "my-app",
|
|
584
|
+
"role": "dev",
|
|
585
|
+
"current_task": "Now writing tests"
|
|
586
|
+
}}
|
|
587
|
+
|
|
588
|
+
// See everyone on the team
|
|
589
|
+
{ "name": "agent_list_team", "arguments": {
|
|
590
|
+
"project": "my-app"
|
|
591
|
+
}}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### How Role Isolation Works
|
|
595
|
+
|
|
596
|
+
- `session_load_context` with `role: "dev"` only sees entries saved with `role: "dev"`
|
|
597
|
+
- The `global` role is a shared pool — anything saved without a role goes here
|
|
598
|
+
- When loading *with* a role, Prism auto-injects a **Team Roster** block listing active teammates, roles, and tasks — no extra tool call needed
|
|
599
|
+
- The Hivemind Radar widget in the Mind Palace dashboard shows agent activity in real time
|
|
600
|
+
|
|
601
|
+
### Setting Your Agent Identity
|
|
602
|
+
|
|
603
|
+
The easiest way to configure your role and name is via the **Mind Palace Dashboard ⚙️ Settings → Agent Identity**:
|
|
604
|
+
|
|
605
|
+
- **Default Role** — dropdown to select `dev`, `qa`, `pm`, `lead`, `security`, `ux`, or `global`
|
|
606
|
+
- **Agent Name** — free text for your display name (e.g. `Dmitri`, `Dev Alex`, `QA Bot`)
|
|
607
|
+
|
|
608
|
+
Once set, **all memory and Hivemind tools automatically use these values** as fallbacks — no need to pass `role` or `agent_name` in every tool call.
|
|
609
|
+
|
|
610
|
+
> **Priority order:** explicit tool arg → dashboard setting → `"global"` (default)
|
|
611
|
+
|
|
612
|
+
**Alternative — hardcode in your startup rules** (if you prefer prompt-level config):
|
|
613
|
+
|
|
614
|
+
```markdown
|
|
615
|
+
## Prism MCP Memory Auto-Load (CRITICAL)
|
|
616
|
+
At the start of every new session, call session_load_context with:
|
|
617
|
+
- project: "my-app", role: "dev"
|
|
618
|
+
- project: "my-other-project", role: "dev"
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
> **Tip:** For true multi-agent setups, each AI instance has its own Mind Palace dashboard — set a different identity per agent there rather than managing it in prompts.
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
479
625
|
## LangChain / LangGraph Integration
|
|
480
626
|
|
|
481
627
|
Prism MCP includes first-class Python adapters for the LangChain ecosystem, located in `examples/langgraph-agent/`:
|
|
@@ -528,7 +674,8 @@ The retrievers use `_aget_relevant_documents` as the primary path with `asyncio.
|
|
|
528
674
|
| Variable | Required | Description |
|
|
529
675
|
|----------|----------|-------------|
|
|
530
676
|
| `BRAVE_API_KEY` | No | Brave Search Pro API key (enables web/local search tools) |
|
|
531
|
-
| `PRISM_STORAGE` | No | `"local"` (default) or `"supabase"` |
|
|
677
|
+
| `PRISM_STORAGE` | No | `"local"` (default) or `"supabase"` — **requires restart** |
|
|
678
|
+
| `PRISM_ENABLE_HIVEMIND` | No | Set `"true"` to enable multi-agent Hivemind tools — **requires restart** |
|
|
532
679
|
| `GOOGLE_API_KEY` | No | Google AI / Gemini — enables paper analysis, Morning Briefings, compaction |
|
|
533
680
|
| `BRAVE_ANSWERS_API_KEY` | No | Separate Brave Answers key for AI-grounded answers |
|
|
534
681
|
| `SUPABASE_URL` | If cloud mode | Supabase project URL |
|
|
@@ -540,6 +687,39 @@ The retrievers use `_aget_relevant_documents` as the primary path with `asyncio.
|
|
|
540
687
|
|
|
541
688
|
---
|
|
542
689
|
|
|
690
|
+
## ⚡ Boot Settings (Restart Required)
|
|
691
|
+
|
|
692
|
+
Some settings affect how Prism **initializes at startup** and cannot be changed at runtime. Prism stores these in a lightweight, dedicated SQLite database (`~/.prism-mcp/prism-config.db`) that is read **before** the main storage backend is selected — solving the chicken-and-egg problem of needing config before the config store is ready.
|
|
693
|
+
|
|
694
|
+
> **⚠️ You must restart the Prism MCP server after changing any Boot Setting.** The Mind Palace dashboard labels these with a **"Restart Required"** badge.
|
|
695
|
+
|
|
696
|
+
| Setting | Dashboard Control | Environment Override | Description |
|
|
697
|
+
|---------|------------------|---------------------|-------------|
|
|
698
|
+
| `PRISM_STORAGE` | ⚙️ Storage Backend dropdown | `PRISM_STORAGE=supabase` | Switch between `local` (SQLite) and `supabase` (cloud) |
|
|
699
|
+
| `PRISM_ENABLE_HIVEMIND` | ⚙️ Hivemind Mode toggle | `PRISM_ENABLE_HIVEMIND=true` | Enable/disable multi-agent coordination tools |
|
|
700
|
+
|
|
701
|
+
### How Boot Settings Work
|
|
702
|
+
|
|
703
|
+
1. **Dashboard saves the setting** → written to `~/.prism-mcp/prism-config.db` immediately
|
|
704
|
+
2. **You restart the MCP server** → server reads the config DB at startup, selects backend/features
|
|
705
|
+
3. **Environment variables always win** → if `PRISM_STORAGE` is set in your MCP config JSON, it overrides the dashboard value
|
|
706
|
+
|
|
707
|
+
```
|
|
708
|
+
Priority: env var in MCP config JSON > Dashboard (prism-config.db) > default (local)
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Runtime Settings (no restart needed)
|
|
712
|
+
|
|
713
|
+
These settings take effect immediately without a restart:
|
|
714
|
+
|
|
715
|
+
| Setting | Description |
|
|
716
|
+
|---------|-------------|
|
|
717
|
+
| Dashboard Theme | Visual theme for the Mind Palace (`dark`, `midnight`, `purple`) |
|
|
718
|
+
| Context Depth | Default level for `session_load_context` (`quick`, `standard`, `deep`) |
|
|
719
|
+
| Auto-Capture HTML | Snapshot local dev server HTML on every handoff save |
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
543
723
|
## Progressive Context Loading
|
|
544
724
|
|
|
545
725
|
Load only what you need — saves tokens and speeds up boot:
|
|
@@ -880,6 +1060,7 @@ See [`vertex-ai/`](vertex-ai/) for setup and benchmarks.
|
|
|
880
1060
|
│ │ ├── interface.ts # StorageBackend abstraction (+ GDPR delete methods)
|
|
881
1061
|
│ │ ├── sqlite.ts # SQLite local storage (libSQL + F32_BLOB + deleted_at migration)
|
|
882
1062
|
│ │ ├── supabase.ts # Supabase cloud storage (+ soft/hard delete)
|
|
1063
|
+
│ │ ├── configStorage.ts # Boot config micro-DB (~/.prism-mcp/prism-config.db)
|
|
883
1064
|
│ │ └── index.ts # Backend factory (auto-selects based on PRISM_STORAGE)
|
|
884
1065
|
│ ├── sync/
|
|
885
1066
|
│ │ ├── interface.ts # SyncBus abstraction (Telepathy)
|
|
@@ -928,10 +1109,19 @@ See [`vertex-ai/`](vertex-ai/) for setup and benchmarks.
|
|
|
928
1109
|
|
|
929
1110
|
> **[View the full project board →](https://github.com/users/dcostenco/projects/1/views/1)**
|
|
930
1111
|
|
|
1112
|
+
### ✅ v3.0.1 — Agent Identity & Brain Clean-up (Shipped!)
|
|
1113
|
+
|
|
1114
|
+
See [What's New in v3.0.1](#whats-new-in-v301---agent-identity--brain-clean-up-) above.
|
|
1115
|
+
|
|
1116
|
+
### ✅ v3.0 — Agent Hivemind (Shipped!)
|
|
1117
|
+
|
|
1118
|
+
See [What's New in v3.0.0 — Agent Hivemind](#whats-new-in-v300---agent-hivemind-) above.
|
|
1119
|
+
|
|
931
1120
|
### 🚀 Future Ideas
|
|
932
1121
|
|
|
933
1122
|
| Feature | Issue | Description |
|
|
934
1123
|
|---------|-------|-------------|
|
|
1124
|
+
| **Role-Scoped Skills & Rules** | — | Each agent role (`dev`, `qa`, `pm`, etc.) gets its own persistent skill/rules document. Preloaded automatically at session start via `session_load_context`. Skills editable and uploadable from the Mind Palace Dashboard (⚙️ → Skills tab per role). Stored in `configStorage` per-role key — backend already exists. |
|
|
935
1125
|
| OpenTelemetry SDK Integration | [#6](https://github.com/dcostenco/prism-mcp/issues/6) | W3C-compliant tracing with Jaeger/Zipkin export |
|
|
936
1126
|
| GDPR Right to Portability | [#7](https://github.com/dcostenco/prism-mcp/issues/7) | `session_export_memory` tool for Art. 20 compliance |
|
|
937
1127
|
| Multi-agent CRDT Conflict Resolution | [#9](https://github.com/dcostenco/prism-mcp/issues/9) | Conflict-free replicated data types for concurrent agent edits |
|
package/dist/config.js
CHANGED
|
@@ -106,6 +106,14 @@ export const PRISM_CAPTURE_PORTS = (process.env.PRISM_CAPTURE_PORTS || "3000,300
|
|
|
106
106
|
// Optionally enable verbose output (stderr) for Prism initialization,
|
|
107
107
|
// memory indexing, and background tasks.
|
|
108
108
|
export const PRISM_DEBUG_LOGGING = process.env.PRISM_DEBUG_LOGGING === "true";
|
|
109
|
+
// ─── v3.0: Agent Hivemind Feature Flag ───────────────────────
|
|
110
|
+
// When enabled, registers 3 additional MCP tools for multi-agent
|
|
111
|
+
// coordination: agent_register, agent_heartbeat, agent_list_team.
|
|
112
|
+
// The role parameter on existing tools (session_save_ledger, etc.)
|
|
113
|
+
// is always available regardless of this flag — adding a parameter
|
|
114
|
+
// doesn't increase tool count.
|
|
115
|
+
// Set PRISM_ENABLE_HIVEMIND=true to unlock the Agent Registry tools.
|
|
116
|
+
export const PRISM_ENABLE_HIVEMIND = process.env.PRISM_ENABLE_HIVEMIND === "true";
|
|
109
117
|
if (PRISM_AUTO_CAPTURE) {
|
|
110
118
|
// Use console.error instead of debugLog here to prevent circular dependency
|
|
111
119
|
if (PRISM_DEBUG_LOGGING) {
|
package/dist/dashboard/server.js
CHANGED
|
@@ -21,7 +21,17 @@ import { exec } from "child_process";
|
|
|
21
21
|
import { getStorage } from "../storage/index.js";
|
|
22
22
|
import { PRISM_USER_ID, SERVER_CONFIG } from "../config.js";
|
|
23
23
|
import { renderDashboardHTML } from "./ui.js";
|
|
24
|
+
import { getAllSettings, setSetting } from "../storage/configStorage.js";
|
|
24
25
|
const PORT = parseInt(process.env.PRISM_DASHBOARD_PORT || "3000", 10);
|
|
26
|
+
/** Read HTTP request body as string */
|
|
27
|
+
function readBody(req) {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
let data = "";
|
|
30
|
+
req.on("data", chunk => { data += chunk; });
|
|
31
|
+
req.on("end", () => resolve(data));
|
|
32
|
+
req.on("error", reject);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
25
35
|
/**
|
|
26
36
|
* Kill any existing process holding the dashboard port.
|
|
27
37
|
* This prevents zombie dashboard processes from surviving IDE restarts
|
|
@@ -65,12 +75,12 @@ async function killPortHolder(port) {
|
|
|
65
75
|
}
|
|
66
76
|
export async function startDashboardServer() {
|
|
67
77
|
// Clean up any zombie dashboard process from a previous session
|
|
68
|
-
killPortHolder(PORT);
|
|
78
|
+
await killPortHolder(PORT);
|
|
69
79
|
const storage = await getStorage();
|
|
70
80
|
const httpServer = http.createServer(async (req, res) => {
|
|
71
81
|
// CORS headers for local dev
|
|
72
82
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
73
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
83
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
74
84
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
75
85
|
if (req.method === "OPTIONS") {
|
|
76
86
|
res.writeHead(204);
|
|
@@ -116,7 +126,7 @@ export async function startDashboardServer() {
|
|
|
116
126
|
return res.end(JSON.stringify({ context, ledger, history }));
|
|
117
127
|
}
|
|
118
128
|
// ─── API: Brain Health Check (v2.2.0) ───
|
|
119
|
-
if (url.pathname === "/api/health") {
|
|
129
|
+
if (url.pathname === "/api/health" && req.method === "GET") {
|
|
120
130
|
try {
|
|
121
131
|
const { runHealthCheck } = await import("../utils/healthCheck.js");
|
|
122
132
|
const stats = await storage.getHealthStats(PRISM_USER_ID);
|
|
@@ -137,6 +147,78 @@ export async function startDashboardServer() {
|
|
|
137
147
|
}));
|
|
138
148
|
}
|
|
139
149
|
}
|
|
150
|
+
// ─── API: Brain Health Cleanup (v3.1) ───
|
|
151
|
+
// Deletes orphaned handoffs (handoffs with no backing ledger entries).
|
|
152
|
+
if (url.pathname === "/api/health/cleanup" && req.method === "POST") {
|
|
153
|
+
try {
|
|
154
|
+
const { runHealthCheck } = await import("../utils/healthCheck.js");
|
|
155
|
+
const stats = await storage.getHealthStats(PRISM_USER_ID);
|
|
156
|
+
const report = runHealthCheck(stats);
|
|
157
|
+
// Collect orphaned handoff projects from the health issues
|
|
158
|
+
const orphaned = stats.orphanedHandoffs || [];
|
|
159
|
+
const cleaned = [];
|
|
160
|
+
for (const { project } of orphaned) {
|
|
161
|
+
try {
|
|
162
|
+
await storage.deleteHandoff(project, PRISM_USER_ID);
|
|
163
|
+
cleaned.push(project);
|
|
164
|
+
console.error(`[Dashboard] Cleaned up orphaned handoff: ${project}`);
|
|
165
|
+
}
|
|
166
|
+
catch (delErr) {
|
|
167
|
+
console.error(`[Dashboard] Failed to delete handoff for ${project}:`, delErr);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
171
|
+
return res.end(JSON.stringify({
|
|
172
|
+
ok: true,
|
|
173
|
+
cleaned,
|
|
174
|
+
count: cleaned.length,
|
|
175
|
+
message: cleaned.length > 0
|
|
176
|
+
? `Cleaned up ${cleaned.length} orphaned handoff(s): ${cleaned.join(", ")}`
|
|
177
|
+
: "No orphaned handoffs to clean up.",
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
console.error("[Dashboard] Health cleanup error:", err);
|
|
182
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
183
|
+
return res.end(JSON.stringify({ ok: false, error: "Cleanup failed" }));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// ─── API: Role-Scoped Skills (v3.1) ───
|
|
187
|
+
// GET /api/skills → { skills: { dev: "...", qa: "..." } }
|
|
188
|
+
if (url.pathname === "/api/skills" && req.method === "GET") {
|
|
189
|
+
const all = await getAllSettings();
|
|
190
|
+
const skills = {};
|
|
191
|
+
for (const [k, v] of Object.entries(all)) {
|
|
192
|
+
if (k.startsWith("skill:") && v) {
|
|
193
|
+
skills[k.replace("skill:", "")] = v;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
197
|
+
return res.end(JSON.stringify({ skills }));
|
|
198
|
+
}
|
|
199
|
+
// POST /api/skills → { role, content } saves skill:<role>
|
|
200
|
+
if (url.pathname === "/api/skills" && req.method === "POST") {
|
|
201
|
+
const body = await new Promise(resolve => {
|
|
202
|
+
let data = "";
|
|
203
|
+
req.on("data", c => data += c);
|
|
204
|
+
req.on("end", () => resolve(data));
|
|
205
|
+
});
|
|
206
|
+
const { role, content } = JSON.parse(body || "{}");
|
|
207
|
+
if (!role) {
|
|
208
|
+
res.writeHead(400);
|
|
209
|
+
return res.end(JSON.stringify({ error: "role required" }));
|
|
210
|
+
}
|
|
211
|
+
await setSetting(`skill:${role}`, content || "");
|
|
212
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
213
|
+
return res.end(JSON.stringify({ ok: true, role }));
|
|
214
|
+
}
|
|
215
|
+
// DELETE /api/skills/:role → clears skill:<role>
|
|
216
|
+
if (url.pathname.startsWith("/api/skills/") && req.method === "DELETE") {
|
|
217
|
+
const role = url.pathname.replace("/api/skills/", "");
|
|
218
|
+
await setSetting(`skill:${role}`, "");
|
|
219
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
220
|
+
return res.end(JSON.stringify({ ok: true, role }));
|
|
221
|
+
}
|
|
140
222
|
// ─── API: Knowledge Graph Data (v2.3.0) ───
|
|
141
223
|
if (url.pathname === "/api/graph") {
|
|
142
224
|
// Fetch recent ledger entries to build the graph
|
|
@@ -199,6 +281,55 @@ export async function startDashboardServer() {
|
|
|
199
281
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
200
282
|
return res.end(JSON.stringify({ nodes, edges }));
|
|
201
283
|
}
|
|
284
|
+
// ─── API: Hivemind Team Roster (v3.0) ───
|
|
285
|
+
if (url.pathname === "/api/team") {
|
|
286
|
+
const projectName = url.searchParams.get("project");
|
|
287
|
+
if (!projectName) {
|
|
288
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
289
|
+
return res.end(JSON.stringify({ error: "Missing ?project= parameter" }));
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const team = await storage.listTeam(projectName, PRISM_USER_ID);
|
|
293
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
294
|
+
return res.end(JSON.stringify({ team }));
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
298
|
+
return res.end(JSON.stringify({ team: [] }));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ─── API: Settings — GET (v3.0 Dashboard Settings) ───
|
|
302
|
+
if (url.pathname === "/api/settings" && req.method === "GET") {
|
|
303
|
+
try {
|
|
304
|
+
const { getAllSettings } = await import("../storage/configStorage.js");
|
|
305
|
+
const settings = await getAllSettings();
|
|
306
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
307
|
+
return res.end(JSON.stringify({ settings }));
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
311
|
+
return res.end(JSON.stringify({ settings: {} }));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// ─── API: Settings — POST (v3.0 Dashboard Settings) ───
|
|
315
|
+
if (url.pathname === "/api/settings" && req.method === "POST") {
|
|
316
|
+
try {
|
|
317
|
+
const body = await readBody(req);
|
|
318
|
+
const parsed = JSON.parse(body);
|
|
319
|
+
if (parsed.key && parsed.value !== undefined) {
|
|
320
|
+
const { setSetting } = await import("../storage/configStorage.js");
|
|
321
|
+
await setSetting(parsed.key, String(parsed.value));
|
|
322
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
323
|
+
return res.end(JSON.stringify({ ok: true, key: parsed.key, value: parsed.value }));
|
|
324
|
+
}
|
|
325
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
326
|
+
return res.end(JSON.stringify({ error: "Missing key or value" }));
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
330
|
+
return res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
202
333
|
// ─── 404 ───
|
|
203
334
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
204
335
|
res.end("Not found");
|