prism-mcp-server 6.2.0 β†’ 6.2.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 CHANGED
@@ -396,7 +396,7 @@ Soft/hard delete (Art. 17), full export in JSON, Markdown, or Obsidian vault `.z
396
396
  ## πŸ†• What's New
397
397
 
398
398
  ### v6.2 β€” The "Synthesize & Prune" Phase βœ…
399
- > **Current stable release (v6.2.0).** The Mind Palace becomes self-organizing.
399
+ > **Current stable release (v6.2.1).** The Mind Palace becomes self-organizing.
400
400
 
401
401
  - πŸ•ΈοΈ **Edge Synthesis ("The Dream Procedure")** β€” Automated background linker discovers semantically similar but disconnected memory nodes via cosine similarity (β‰₯ 0.7 threshold). Batch-limited to 50 sources Γ— 3 neighbors. New `session_synthesize_edges` tool for on-demand graph enrichment.
402
402
  - βœ‚οΈ **Graph Pruning (Soft-Prune)** β€” Configurable strength-based pruning soft-deletes weak links. Includes per-project cooldown, backpressure guards, and sweep budget controls. Enable with `PRISM_GRAPH_PRUNING_ENABLED=true`.
@@ -1322,6 +1322,17 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
1322
1322
  <div class="toast-fixed" id="fixedToast"></div>
1323
1323
 
1324
1324
  <script>
1325
+ // ═══════════════════════════════════════════════════════════════════
1326
+ // COMPATIBILITY RULE: This entire <script> block MUST use ES5 only.
1327
+ // - Use 'var' (NEVER 'const' or 'let')
1328
+ // - Use 'function(){}' (NEVER '=>' arrow functions)
1329
+ // - NO optional chaining '?.'
1330
+ // - NO template literals (backticks) β€” use string concatenation
1331
+ // - NO destructuring, spread, or other ES6+ syntax
1332
+ // This HTML is served as a raw template literal; mixing ES6 in the
1333
+ // inline script causes SyntaxError in some browser/context combos.
1334
+ // ═══════════════════════════════════════════════════════════════════
1335
+
1325
1336
  // ─── TABS & SEARCH (v6.0) ───
1326
1337
  function switchMainTab(tabId) {
1327
1338
  document.getElementById('mtab-project').classList.toggle('active', tabId === 'project');
@@ -1337,14 +1348,14 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
1337
1348
  }
1338
1349
  }
1339
1350
 
1340
- let searchTimeout = null;
1341
- let searchAbortController = null;
1351
+ var searchTimeout = null;
1352
+ var searchAbortController = null;
1342
1353
 
1343
1354
  async function performSearch() {
1344
- const input = document.getElementById('searchInput');
1345
- const boost = document.getElementById('searchContextBoost');
1346
- const resultsDiv = document.getElementById('searchResults');
1347
- const query = input.value.trim();
1355
+ var input = document.getElementById('searchInput');
1356
+ var boost = document.getElementById('searchContextBoost');
1357
+ var resultsDiv = document.getElementById('searchResults');
1358
+ var query = input.value.trim();
1348
1359
 
1349
1360
  if (!query) {
1350
1361
  if (searchAbortController) searchAbortController.abort();
@@ -1354,17 +1365,17 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
1354
1365
 
1355
1366
  resultsDiv.innerHTML = '<div class="loading" style="padding:2rem;"><span class="spinner"></span> Searching neural memory via embeddings...</div>';
1356
1367
 
1357
- const project = document.getElementById('projectSelect').value;
1358
- let url = \`/api/search?q=\${encodeURIComponent(query)}\`;
1359
- if (project) url += \`&project=\${encodeURIComponent(project)}\`;
1360
- if (boost.checked) url += \`&boost=true\`;
1368
+ var project = document.getElementById('projectSelect').value;
1369
+ var url = '/api/search?q=' + encodeURIComponent(query);
1370
+ if (project) url += '&project=' + encodeURIComponent(project);
1371
+ if (boost.checked) url += '&boost=true';
1361
1372
 
1362
1373
  if (searchAbortController) searchAbortController.abort();
1363
1374
  searchAbortController = new AbortController();
1364
1375
 
1365
1376
  try {
1366
- const res = await fetch(url, { signal: searchAbortController.signal });
1367
- const data = await res.json();
1377
+ var res = await fetch(url, { signal: searchAbortController.signal });
1378
+ var data = await res.json();
1368
1379
  if (data.error) throw new Error(data.error);
1369
1380
 
1370
1381
  if (!data.results || data.results.length === 0) {
@@ -1373,55 +1384,58 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
1373
1384
  }
1374
1385
 
1375
1386
  // Extract searchable terms for highlighting (length > 2)
1376
- const queryTerms = query.split(/\\s+/).filter(w => w.length > 2);
1377
- const termRegex = queryTerms.length > 0
1378
- ? new RegExp(\`(\${queryTerms.map(w => w.replace(/[.*+?^$()|[\\]\\\\{}]/g, '\\\\$&')).join('|')})\`, 'gi')
1387
+ var queryTerms = query.split(/\\s+/).filter(function(w) { return w.length > 2; });
1388
+ var termRegex = queryTerms.length > 0
1389
+ ? new RegExp('(' + queryTerms.map(function(w) { return w.replace(/[.*+?^$()|[\\]\\\\{}]/g, '\\\\$&'); }).join('|') + ')', 'gi')
1379
1390
  : null;
1380
1391
 
1381
1392
  function highlight(text) {
1382
- let escaped = escapeHtml(text || '');
1393
+ var escaped = escapeHtml(text || '');
1383
1394
  if (termRegex) {
1384
1395
  escaped = escaped.replace(termRegex, '<mark style="background: rgba(168, 85, 247, 0.4); color: inherit; padding: 0 0.1rem; border-radius: 2px;">$1</mark>');
1385
1396
  }
1386
1397
  return escaped;
1387
1398
  }
1388
1399
 
1389
- resultsDiv.innerHTML = data.results.map(r => {
1390
- const isGraduated = r.importance >= 7;
1391
- const opacity = isGraduated ? 1 : 0.8;
1392
- const borderStyle = isGraduated ? 'border-left: 3px solid var(--accent-purple); padding-left: 0.8rem;' : '';
1393
-
1394
- return \`<div class="entry" style="opacity: \${opacity}; \${borderStyle}">
1395
- <div class="entry-meta" style="justify-content:space-between; margin-bottom:0.5rem;">
1396
- <span>πŸ“ \${escapeHtml(r.project)} β€’ πŸ•’ \${new Date(r.session_date || r.created_at || Date.now()).toLocaleDateString()}</span>
1397
- <div style="display:flex; gap:0.5rem; font-size:0.75rem;">
1398
- <!-- Similarity is how closely the vector matches the conceptual query -->
1399
- <span class="badge" title="Similarity Score (Semantic Match)" style="background:rgba(6,182,212,0.1); color:var(--accent-cyan); border:1px solid rgba(6,182,212,0.3);">
1400
- 🎯 \${(r.similarity * 100).toFixed(1)}%
1401
- </span>
1402
- <!-- Importance is our Ebbinghaus decaying stat (frequency vs recency) -->
1403
- <span class="badge badge-purple" title="Ebbinghaus Importance (Recency/Reinforcement)">
1404
- ⭐ \${(r.importance || 0).toFixed(1)}
1405
- </span>
1406
- </div>
1407
- </div>
1408
- <div class="entry-summary" style="font-size:0.9rem; line-height: 1.5;">\${highlight(r.summary)}</div>
1409
- \${r.decisions && r.decisions.length > 0
1410
- ? \`<ul class="tag-list" style="margin-top:0.75rem;">\${r.decisions.map(d => \`<li class="tag">πŸ’‘ \${highlight(d)}</li>\`).join('')}</ul>\`
1411
- : ''}
1412
- </div>\`;
1400
+ resultsDiv.innerHTML = data.results.map(function(r) {
1401
+ var isGraduated = r.importance >= 7;
1402
+ var opacity = isGraduated ? 1 : 0.8;
1403
+ var borderStyle = isGraduated ? 'border-left: 3px solid var(--accent-purple); padding-left: 0.8rem;' : '';
1404
+ var decisionsHtml = '';
1405
+ if (r.decisions && r.decisions.length > 0) {
1406
+ decisionsHtml = '<ul class="tag-list" style="margin-top:0.75rem;">' +
1407
+ r.decisions.map(function(d) { return '<li class="tag">πŸ’‘ ' + highlight(d) + '</li>'; }).join('') +
1408
+ '</ul>';
1409
+ }
1410
+ return '<div class="entry" style="opacity: ' + opacity + '; ' + borderStyle + '">' +
1411
+ '<div class="entry-meta" style="justify-content:space-between; margin-bottom:0.5rem;">' +
1412
+ '<span>πŸ“ ' + escapeHtml(r.project) + ' β€’ πŸ•’ ' + new Date(r.session_date || r.created_at || Date.now()).toLocaleDateString() + '</span>' +
1413
+ '<div style="display:flex; gap:0.5rem; font-size:0.75rem;">' +
1414
+ '<span class="badge" title="Similarity Score (Semantic Match)" style="background:rgba(6,182,212,0.1); color:var(--accent-cyan); border:1px solid rgba(6,182,212,0.3);">' +
1415
+ '🎯 ' + (r.similarity * 100).toFixed(1) + '%' +
1416
+ '</span>' +
1417
+ '<span class="badge badge-purple" title="Ebbinghaus Importance (Recency/Reinforcement)">' +
1418
+ '⭐ ' + (r.importance || 0).toFixed(1) +
1419
+ '</span>' +
1420
+ '</div>' +
1421
+ '</div>' +
1422
+ '<div class="entry-summary" style="font-size:0.9rem; line-height: 1.5;">' + highlight(r.summary) + '</div>' +
1423
+ decisionsHtml +
1424
+ '</div>';
1413
1425
  }).join('');
1414
1426
  } catch (err) {
1415
1427
  if (err.name === 'AbortError') return; // Ignore aborted fetches
1416
- resultsDiv.innerHTML = \`<div style="padding:1rem; color:var(--accent-rose);">❌ Failed to search memory: \${escapeHtml(err.message)}</div>\`;
1428
+ resultsDiv.innerHTML = '<div style="padding:1rem; color:var(--accent-rose);">❌ Failed to search memory: ' + escapeHtml(err.message) + '</div>';
1417
1429
  }
1418
1430
  }
1419
1431
 
1420
- document.getElementById('searchInput')?.addEventListener('input', () => {
1432
+ var _searchInput = document.getElementById('searchInput');
1433
+ if (_searchInput) _searchInput.addEventListener('input', function() {
1421
1434
  clearTimeout(searchTimeout);
1422
1435
  searchTimeout = setTimeout(performSearch, 300);
1423
1436
  });
1424
- document.getElementById('searchContextBoost')?.addEventListener('change', performSearch);
1437
+ var _searchBoost = document.getElementById('searchContextBoost');
1438
+ if (_searchBoost) _searchBoost.addEventListener('change', performSearch);
1425
1439
 
1426
1440
 
1427
1441
  // Role icon map
@@ -1451,9 +1465,9 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
1451
1465
  // Auto-load project list on page load
1452
1466
  (async function() {
1453
1467
  try {
1454
- const res = await fetch('/api/projects');
1455
- const data = await res.json();
1456
- const select = document.getElementById('projectSelect');
1468
+ var res = await fetch('/api/projects');
1469
+ var data = await res.json();
1470
+ var select = document.getElementById('projectSelect');
1457
1471
  if (data.projects && data.projects.length > 0) {
1458
1472
  select.innerHTML = '<option value="">β€” Select a project β€”</option>' +
1459
1473
  data.projects.map(function(p) { return '<option value="' + p + '">' + p + '</option>'; }).join('');
@@ -2318,25 +2332,27 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
2318
2332
  }
2319
2333
 
2320
2334
  async function triggerEdgeSynthesis() {
2321
- const project = document.getElementById('graphProjectFilter')?.value || document.getElementById('projectSelect')?.value;
2335
+ var gpf = document.getElementById('graphProjectFilter');
2336
+ var ps = document.getElementById('projectSelect');
2337
+ var project = (gpf ? gpf.value : '') || (ps ? ps.value : '');
2322
2338
  if (!project) {
2323
2339
  alert("Please select an active project first.");
2324
2340
  return;
2325
2341
  }
2326
2342
 
2327
- const btn = document.querySelector('button[onclick="triggerEdgeSynthesis()"]');
2328
- const status = document.getElementById('synthesisStatus');
2343
+ var btn = document.querySelector('button[onclick="triggerEdgeSynthesis()"]');
2344
+ var status = document.getElementById('synthesisStatus');
2329
2345
  if (btn) { btn.disabled = true; btn.style.opacity = '0.5'; }
2330
2346
  if (status) status.textContent = 'running...';
2331
2347
 
2332
2348
  try {
2333
- const res = await fetch('/api/graph/synthesize', {
2349
+ var res = await fetch('/api/graph/synthesize', {
2334
2350
  method: 'POST',
2335
2351
  headers: { 'Content-Type': 'application/json' },
2336
2352
  body: JSON.stringify({ project: project, randomize_selection: true, max_entries: 50 })
2337
2353
  });
2338
2354
 
2339
- const data = await res.json();
2355
+ var data = await res.json();
2340
2356
  if (res.ok && data.success) {
2341
2357
  if (status) status.textContent = 'βœ… Created ' + data.newLinks + ' links (Scanned: ' + data.entriesScanned + ')';
2342
2358
  setTimeout(loadGraph, 1000); // Reload graph to show new edges
@@ -2360,7 +2376,9 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
2360
2376
  async function triggerTestMe() {
2361
2377
  var input = document.getElementById('nodeEditorInput');
2362
2378
  var oldId = input.dataset.oldId;
2363
- var project = document.getElementById('graphProjectFilter')?.value || document.getElementById('projectSelect')?.value;
2379
+ var _gpf = document.getElementById('graphProjectFilter');
2380
+ var _ps = document.getElementById('projectSelect');
2381
+ var project = (_gpf ? _gpf.value : '') || (_ps ? _ps.value : '');
2364
2382
 
2365
2383
  if (!oldId || !project) return;
2366
2384
 
@@ -2410,7 +2428,7 @@ Example:\n## Dev Rules\n- Always write tests first\n- Use TypeScript strict mode
2410
2428
  '<div class="testme-ans" style="display:none; font-size:0.75rem; color:var(--text-secondary); margin-top:0.4rem; padding-top:0.4rem; border-top:1px dashed var(--border-subtle);">' +
2411
2429
  escapeHtml(qa.a) +
2412
2430
  '</div>' +
2413
- '<button onclick="this.previousElementSibling.style.display=\'block\'; this.style.display=\'none\'" style="background:transparent; border:none; color:var(--accent-purple); font-size:0.7rem; cursor:pointer; padding:0; margin-top:0.3rem;">Show Answer</button>';
2431
+ '<button onclick="this.previousElementSibling.style.display=&apos;block&apos;; this.style.display=&apos;none&apos;" style="background:transparent; border:none; color:var(--accent-purple); font-size:0.7rem; cursor:pointer; padding:0; margin-top:0.3rem;">Show Answer</button>';
2414
2432
 
2415
2433
  container.appendChild(card);
2416
2434
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
4
4
  "mcpName": "io.github.dcostenco/prism-mcp",
5
5
  "description": "The Mind Palace for AI Agents β€” persistent memory (SQLite/Supabase), behavioral learning & IDE rules sync, multimodal VLM image captioning, pluggable LLM providers (OpenAI/Anthropic/Gemini/Ollama), OpenTelemetry distributed tracing, GDPR export, multi-agent Hivemind sync, time travel, visual Mind Palace dashboard. Zero-config local mode.",
6
6
  "module": "index.ts",