prism-mcp-server 9.2.0 → 9.2.2
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 +21 -4
- package/dist/cli.js +58 -40
- package/dist/tools/ledgerHandlers.js +63 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -278,6 +278,13 @@ bash ~/.gemini/antigravity/scratch/prism_session_loader.sh my-project
|
|
|
278
278
|
|
|
279
279
|
The CLI uses the same storage layer as the MCP tool (SQLite or Supabase).
|
|
280
280
|
|
|
281
|
+
> ⚠️ **CRITICAL (v9.2.2): Split-Brain Prevention**
|
|
282
|
+
> If your MCP server is configured with `PRISM_STORAGE=local` but Supabase credentials are also set, the CLI may read from the **wrong backend** (Supabase) while the server writes to SQLite. This causes stale TODOs and divergent state. Always pass `--storage local` explicitly when using the CLI in a local-mode environment:
|
|
283
|
+
> ```bash
|
|
284
|
+
> prism load my-project --storage local --json
|
|
285
|
+
> ```
|
|
286
|
+
> The `prism_session_loader.sh` wrapper handles this automatically since v9.2.2.
|
|
287
|
+
|
|
281
288
|
</details>
|
|
282
289
|
|
|
283
290
|
<details>
|
|
@@ -295,6 +302,10 @@ SUMMARY=$(echo "$CONTEXT" | jq -r '.handoff[0].last_summary')
|
|
|
295
302
|
VERSION=$(echo "$CONTEXT" | jq -r '.handoff[0].version')
|
|
296
303
|
echo "Project at v$VERSION: $SUMMARY"
|
|
297
304
|
|
|
305
|
+
# Explicit storage backend (v9.2.2 — prevents split-brain)
|
|
306
|
+
prism load my-project --storage local --json
|
|
307
|
+
prism load my-project --storage supabase --json
|
|
308
|
+
|
|
298
309
|
# Role-scoped loading
|
|
299
310
|
prism load my-project --role qa --json
|
|
300
311
|
|
|
@@ -778,8 +789,10 @@ The Generator strips the `console.log`, resubmits, and the next `EVALUATE` retur
|
|
|
778
789
|
|
|
779
790
|
## 🆕 What's New
|
|
780
791
|
|
|
781
|
-
> **Current release: v9.
|
|
792
|
+
> **Current release: v9.2.2 — Critical Split-Brain Fix**
|
|
782
793
|
|
|
794
|
+
- 🚨 **v9.2.2 — Critical: Split-Brain Detection & Prevention:** When multiple MCP clients use different storage backends (e.g., Claude Desktop → Supabase, Antigravity → SQLite), session state could silently diverge, causing agents to act on stale TODOs and outdated context. **New: `--storage` flag** on `prism load` CLI lets callers explicitly select which backend to read from. **New: Split-Brain Drift Detection** in `session_load_context` — compares active and alternate backend versions at load time and warns prominently when they diverge. Session loader script updated to respect `PRISM_STORAGE` environment variable.
|
|
795
|
+
- 💻 **v9.2.1 — CLI Full Feature Parity:** `prism load` text mode now delegates to the real `session_load_context` handler, giving CLI-only users the same enriched output as MCP clients: morning briefings, reality drift detection, SDM intuitive recall, visual memory index, role-scoped skill injection, behavioral warnings, importance scores, and agent identity. JSON mode now includes `agent_name` from dashboard settings. Session loader script PATH fix for Homebrew/nvm/volta environments.
|
|
783
796
|
- 🚦 **v9.1.0 — Task Router v2:** File-type complexity signal for intelligent code-vs-config routing, 6-signal weighted heuristic engine, multi-step false-positive fix, expanded file extension classification. Local agent hardened with buffered streaming, system prompts, memory trimming, and stateful `/api/chat` API.
|
|
784
797
|
- 🔒 **v9.0.5 — JWKS Auth Security Hardening:** JWT audience/issuer claim validation (`PRISM_JWT_AUDIENCE`, `PRISM_JWT_ISSUER`), structured error logging for JWT failures, typed `PrismAuthenticatedRequest` interface, 11 new JWKS unit tests, Smithery server card fix. Vendor-neutral — tested with Auth0, AgentLair ([llms.txt](https://agentlair.com/llms.txt)), Keycloak, and custom JWKS endpoints.
|
|
785
798
|
- 🧠 **v9.0.0 — Autonomous Cognitive OS:** Token-Economic Reinforcement Learning (Surprisal Gate + Cognitive Budget), Affect-Tagged Memory (valence-scored retrieval), and Episodic→Semantic Consolidation. Your agents learn compression and develop intuition. → [Cognitive OS](#-autonomous-cognitive-os-v90)
|
|
@@ -844,12 +857,16 @@ Every other AI coding pipeline has a fatal flaw: it asks the same model that wro
|
|
|
844
857
|
|
|
845
858
|
## 💻 CLI Reference
|
|
846
859
|
|
|
847
|
-
Prism includes a CLI for environments where MCP tools aren't available (CI/CD pipelines, Bash scripts, non-MCP IDEs like Antigravity)
|
|
860
|
+
Prism includes a CLI for environments where MCP tools aren't available (CI/CD pipelines, Bash scripts, non-MCP IDEs like Antigravity).
|
|
861
|
+
|
|
862
|
+
**Text mode** delegates to the real `session_load_context` handler — full feature parity with MCP clients, including morning briefings, reality drift detection, SDM intuitive recall, visual memory, role-scoped skills, behavioral warnings, and agent identity.
|
|
863
|
+
|
|
864
|
+
**JSON mode** emits a structured envelope for programmatic consumption (scripts, CI/CD, session loaders).
|
|
848
865
|
|
|
849
866
|
```bash
|
|
850
|
-
# Load session context (same
|
|
867
|
+
# Load session context (full enrichments — same as MCP tool)
|
|
851
868
|
prism load my-project # Human-readable, standard depth
|
|
852
|
-
prism load my-project --level deep # Full context
|
|
869
|
+
prism load my-project --level deep # Full context with all enrichments
|
|
853
870
|
prism load my-project --level quick --json # Machine-readable JSON
|
|
854
871
|
prism load my-project --role dev --json # Role-scoped loading
|
|
855
872
|
|
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { getStorage, closeStorage } from './storage/index.js';
|
|
|
7
7
|
import { getSetting } from './storage/configStorage.js';
|
|
8
8
|
import { PRISM_USER_ID, SERVER_CONFIG } from './config.js';
|
|
9
9
|
import { getCurrentGitState } from './utils/git.js';
|
|
10
|
+
import { sessionLoadContextHandler } from './tools/ledgerHandlers.js';
|
|
10
11
|
const program = new Command();
|
|
11
12
|
program
|
|
12
13
|
.name('prism')
|
|
@@ -17,41 +18,64 @@ program
|
|
|
17
18
|
// session_load_context tool. Works with both SQLite and Supabase.
|
|
18
19
|
// Designed for environments that cannot use MCP tools directly
|
|
19
20
|
// (Antigravity, Bash scripts, CI/CD pipelines).
|
|
21
|
+
//
|
|
22
|
+
// CRITICAL: --storage flag (v9.2.2)
|
|
23
|
+
// When multiple MCP clients use different storage backends (e.g.
|
|
24
|
+
// Claude Desktop → Supabase, Antigravity → SQLite), the CLI must
|
|
25
|
+
// be told which backend to read from. Without this, the CLI
|
|
26
|
+
// inherits PRISM_STORAGE from the shell env (defaulting to
|
|
27
|
+
// supabase), which may differ from the MCP server's config.
|
|
28
|
+
// This causes a "split-brain" where the CLI returns stale state
|
|
29
|
+
// from the wrong backend.
|
|
30
|
+
//
|
|
31
|
+
// TEXT MODE: Delegates to the real sessionLoadContextHandler for
|
|
32
|
+
// full feature parity — morning briefing, reality drift detection,
|
|
33
|
+
// SDM recall, visual memory, skill injection, behavioral warnings,
|
|
34
|
+
// importance scores, recent validations. Any future MCP enrichments
|
|
35
|
+
// automatically appear in CLI too.
|
|
36
|
+
//
|
|
37
|
+
// JSON MODE: Structured envelope for programmatic consumption
|
|
38
|
+
// (session loader scripts, CI/CD pipelines, etc.).
|
|
20
39
|
program
|
|
21
40
|
.command('load <project>')
|
|
22
41
|
.description('Load session context for a project (same output as session_load_context MCP tool)')
|
|
23
42
|
.option('-l, --level <level>', 'Context depth: quick, standard, deep', 'standard')
|
|
24
43
|
.option('-r, --role <role>', 'Role scope for context loading')
|
|
44
|
+
.option('-s, --storage <backend>', 'Storage backend: local (SQLite) or supabase. Overrides PRISM_STORAGE env var.')
|
|
25
45
|
.option('--json', 'Emit machine-readable JSON instead of formatted text')
|
|
26
46
|
.action(async (project, options) => {
|
|
27
47
|
try {
|
|
28
|
-
const { level, role, json: jsonOutput } = options;
|
|
48
|
+
const { level, role, storage, json: jsonOutput } = options;
|
|
49
|
+
// v9.2.2: --storage flag overrides PRISM_STORAGE env var to prevent
|
|
50
|
+
// split-brain when CLI environment differs from MCP server config.
|
|
51
|
+
if (storage) {
|
|
52
|
+
const validStorages = ['local', 'supabase'];
|
|
53
|
+
if (!validStorages.includes(storage)) {
|
|
54
|
+
console.error(`Error: Invalid storage "${storage}". Must be one of: ${validStorages.join(', ')}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
process.env.PRISM_STORAGE = storage;
|
|
58
|
+
}
|
|
29
59
|
const validLevels = ['quick', 'standard', 'deep'];
|
|
30
60
|
if (!validLevels.includes(level)) {
|
|
31
61
|
console.error(`Error: Invalid level "${level}". Must be one of: ${validLevels.join(', ')}`);
|
|
32
62
|
process.exit(1);
|
|
33
63
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
if (jsonOutput) {
|
|
65
|
+
// ── JSON mode: structured output for programmatic consumption ──
|
|
66
|
+
const storageBackend = await getStorage();
|
|
67
|
+
const effectiveRole = role || await getSetting('default_role', '') || undefined;
|
|
68
|
+
const agentName = await getSetting('agent_name', '') || undefined;
|
|
69
|
+
const data = await storageBackend.loadContext(project, level, PRISM_USER_ID, effectiveRole);
|
|
70
|
+
if (!data) {
|
|
40
71
|
console.log(JSON.stringify({ error: `No session context found for project "${project}"` }));
|
|
72
|
+
await closeStorage();
|
|
73
|
+
process.exit(0);
|
|
41
74
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
console.log('This project has no previous session history. Starting fresh.');
|
|
45
|
-
}
|
|
46
|
-
await closeStorage();
|
|
47
|
-
process.exit(0);
|
|
48
|
-
}
|
|
49
|
-
const d = data;
|
|
50
|
-
// Gather git state for enrichment
|
|
51
|
-
const gitState = getCurrentGitState();
|
|
52
|
-
if (jsonOutput) {
|
|
53
|
-
// Machine-readable JSON envelope — matches what prism_session_loader.sh produced
|
|
75
|
+
const d = data;
|
|
76
|
+
const gitState = getCurrentGitState();
|
|
54
77
|
const output = {
|
|
78
|
+
agent_name: agentName || null,
|
|
55
79
|
handoff: [{
|
|
56
80
|
project,
|
|
57
81
|
role: effectiveRole || d.role || 'global',
|
|
@@ -77,29 +101,23 @@ program
|
|
|
77
101
|
console.log(JSON.stringify(output, null, 2));
|
|
78
102
|
}
|
|
79
103
|
else {
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
if (d.active_decisions?.length) {
|
|
92
|
-
output += `\n⚖️ Active Decisions:\n` + d.active_decisions.map((dec) => ` - ${dec}`).join('\n') + '\n';
|
|
93
|
-
}
|
|
94
|
-
if (d.keywords?.length) {
|
|
95
|
-
output += `\n🔑 Keywords: ${d.keywords.join(', ')}\n`;
|
|
96
|
-
}
|
|
97
|
-
if (d.recent_sessions?.length) {
|
|
98
|
-
output += `\n⏳ Recent Sessions:\n` + d.recent_sessions.map((s) => ` [${s.session_date?.split('T')[0]}] ${s.summary}`).join('\n') + '\n';
|
|
104
|
+
// ── Text mode: full parity with MCP session_load_context ──
|
|
105
|
+
// Delegates to the real handler so all enrichments (morning briefing,
|
|
106
|
+
// reality drift, SDM recall, visual memory, skill injection,
|
|
107
|
+
// behavioral warnings, etc.) are included automatically.
|
|
108
|
+
const result = await sessionLoadContextHandler({ project, level, role });
|
|
109
|
+
// Surface handler-level errors (e.g. invalid args, storage failures)
|
|
110
|
+
if (result.isError) {
|
|
111
|
+
console.error(result.content[0]?.text || 'Unknown error loading context');
|
|
112
|
+
await closeStorage();
|
|
113
|
+
process.exit(1);
|
|
99
114
|
}
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
let output = '';
|
|
116
|
+
if (result.content?.[0]) {
|
|
117
|
+
output = result.content[0].text;
|
|
102
118
|
}
|
|
119
|
+
// Append git state (not included in the MCP handler output)
|
|
120
|
+
const gitState = getCurrentGitState();
|
|
103
121
|
if (gitState.isRepo) {
|
|
104
122
|
output += `\n\n🔧 Git: ${gitState.branch} @ ${gitState.commitSha?.substring(0, 7)} (Prism v${SERVER_CONFIG.version})`;
|
|
105
123
|
}
|
|
@@ -23,7 +23,7 @@ import { buildVaultDirectory } from "../utils/vaultExporter.js";
|
|
|
23
23
|
* ═══════════════════════════════════════════════════════════════════
|
|
24
24
|
*/
|
|
25
25
|
import { debugLog } from "../utils/logger.js";
|
|
26
|
-
import { getStorage } from "../storage/index.js";
|
|
26
|
+
import { getStorage, activeStorageBackend } from "../storage/index.js";
|
|
27
27
|
import { toKeywordArray } from "../utils/keywordExtractor.js";
|
|
28
28
|
import { getLLMProvider } from "../utils/llm/factory.js";
|
|
29
29
|
import { getCurrentGitState, getGitDrift } from "../utils/git.js";
|
|
@@ -524,6 +524,67 @@ export async function sessionLoadContextHandler(args) {
|
|
|
524
524
|
const versionNote = version
|
|
525
525
|
? `\n\n🔑 Session version: ${version}. Pass expected_version: ${version} when saving handoff.`
|
|
526
526
|
: "";
|
|
527
|
+
// ─── v9.2.2: Split-Brain Drift Detection ───────────────────
|
|
528
|
+
// When using one storage backend (e.g. SQLite), check if an
|
|
529
|
+
// alternate backend (e.g. Supabase) exists with a different
|
|
530
|
+
// version. This prevents agents from unknowingly acting on
|
|
531
|
+
// stale state from a diverged backend.
|
|
532
|
+
//
|
|
533
|
+
// PERF NOTE: We do NOT construct a full StorageBackend for the
|
|
534
|
+
// alternate check — that would trigger full migrations/schema
|
|
535
|
+
// validation on every load (~200-1000ms). Instead we use
|
|
536
|
+
// lightweight direct queries: REST GET for Supabase, raw SQL
|
|
537
|
+
// for SQLite. This keeps the check under ~100ms.
|
|
538
|
+
let splitBrainWarning = "";
|
|
539
|
+
try {
|
|
540
|
+
const { SUPABASE_CONFIGURED, SUPABASE_URL, SUPABASE_KEY } = await import("../config.js");
|
|
541
|
+
if (activeStorageBackend === "local" && SUPABASE_CONFIGURED && SUPABASE_URL && SUPABASE_KEY) {
|
|
542
|
+
// Lightweight Supabase version check via REST (no full init/migrations)
|
|
543
|
+
const { supabaseGet } = await import("../utils/supabaseApi.js");
|
|
544
|
+
const rows = await supabaseGet("session_handoffs", {
|
|
545
|
+
project: `eq.${project}`,
|
|
546
|
+
select: "version",
|
|
547
|
+
limit: "1",
|
|
548
|
+
});
|
|
549
|
+
const altVersion = Array.isArray(rows) && rows[0] ? rows[0].version : null;
|
|
550
|
+
if (altVersion && altVersion !== version) {
|
|
551
|
+
splitBrainWarning = `\n\n⚠️ **SPLIT-BRAIN DETECTED** (v${version} local vs v${altVersion} cloud)\n` +
|
|
552
|
+
`Your local SQLite state (v${version}) differs from the Supabase cloud state (v${altVersion}). ` +
|
|
553
|
+
`This means another client (e.g. Claude Desktop) has saved state that this environment cannot see. ` +
|
|
554
|
+
`TODOs, summaries, and decisions may be stale. Please reconcile by running:\n` +
|
|
555
|
+
` \`prism load ${project} --storage supabase\` to see the cloud state.`;
|
|
556
|
+
debugLog(`[session_load_context] SPLIT-BRAIN: local v${version} vs supabase v${altVersion}`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
else if (activeStorageBackend === "supabase") {
|
|
560
|
+
// Lightweight SQLite version check via direct file query (no full init/migrations)
|
|
561
|
+
const dbPath = nodePath.join(os.homedir(), ".prism-mcp", "data.db");
|
|
562
|
+
if (fs.existsSync(dbPath)) {
|
|
563
|
+
let altClient = null;
|
|
564
|
+
try {
|
|
565
|
+
const { createClient } = await import("@libsql/client");
|
|
566
|
+
altClient = createClient({ url: `file:${dbPath}` });
|
|
567
|
+
const result = await altClient.execute(`SELECT version FROM session_handoffs WHERE project = ? LIMIT 1`, [project]);
|
|
568
|
+
const altVersion = result.rows?.[0]?.version;
|
|
569
|
+
if (altVersion && altVersion !== version) {
|
|
570
|
+
splitBrainWarning = `\n\n⚠️ **SPLIT-BRAIN DETECTED** (v${version} cloud vs v${altVersion} local)\n` +
|
|
571
|
+
`Your Supabase cloud state (v${version}) differs from the local SQLite state (v${altVersion}). ` +
|
|
572
|
+
`This means another client has saved state that this environment cannot see. ` +
|
|
573
|
+
`TODOs, summaries, and decisions may be stale. Please reconcile by running:\n` +
|
|
574
|
+
` \`prism load ${project} --storage local\` to see the local state.`;
|
|
575
|
+
debugLog(`[session_load_context] SPLIT-BRAIN: supabase v${version} vs local v${altVersion}`);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
finally {
|
|
579
|
+
if (altClient)
|
|
580
|
+
altClient.close();
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
catch (err) {
|
|
586
|
+
debugLog(`[session_load_context] Split-brain check failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
587
|
+
}
|
|
527
588
|
// ─── Reality Drift Detection (v2.0 Step 5) ───
|
|
528
589
|
// Check if the developer changed code since the last handoff save.
|
|
529
590
|
let driftReport = "";
|
|
@@ -721,7 +782,7 @@ export async function sessionLoadContextHandler(args) {
|
|
|
721
782
|
}
|
|
722
783
|
}
|
|
723
784
|
// Build the response object before v4.0 augmentations
|
|
724
|
-
let responseText = `📋 Session context for "${project}" (${level}):\n\n${formattedContext.trim()}${driftReport}${briefingBlock}${sdmRecallBlock}${greetingBlock}${visualMemoryBlock}${skillBlock}${versionNote}`;
|
|
785
|
+
let responseText = `📋 Session context for "${project}" (${level}):\n\n${formattedContext.trim()}${splitBrainWarning}${driftReport}${briefingBlock}${sdmRecallBlock}${greetingBlock}${visualMemoryBlock}${skillBlock}${versionNote}`;
|
|
725
786
|
// ─── v4.0: Behavioral Warnings Injection ───────────────────
|
|
726
787
|
// If loadContext returned behavioral_warnings, add them to the
|
|
727
788
|
// formatted output so the agent sees them prominently.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-mcp",
|
|
5
5
|
"description": "The Mind Palace for AI Agents — a true Cognitive Architecture with Hebbian learning (episodic→semantic consolidation), ACT-R spreading activation (multi-hop causal reasoning), uncertainty-aware rejection gates (agents that know when they don't know), adversarial evaluation (anti-sycophancy), fail-closed Dark Factory pipelines, persistent memory (SQLite/Supabase), multi-agent Hivemind, time travel & visual dashboard. Zero-config local mode.",
|
|
6
6
|
"module": "index.ts",
|