laminark 2.21.7 → 2.21.9

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.
Files changed (52) hide show
  1. package/README.md +36 -71
  2. package/package.json +9 -7
  3. package/plugin/.claude-plugin/plugin.json +1 -1
  4. package/plugin/CLAUDE.md +10 -0
  5. package/plugin/commands/recall.md +55 -0
  6. package/plugin/commands/remember.md +34 -0
  7. package/plugin/commands/resume.md +45 -0
  8. package/plugin/commands/stash.md +34 -0
  9. package/plugin/commands/status.md +33 -0
  10. package/plugin/dist/hooks/handler.d.ts +3 -1
  11. package/plugin/dist/hooks/handler.d.ts.map +1 -1
  12. package/plugin/dist/hooks/handler.js +312 -23
  13. package/plugin/dist/hooks/handler.js.map +1 -1
  14. package/plugin/dist/index.d.ts +3 -1
  15. package/plugin/dist/index.d.ts.map +1 -1
  16. package/plugin/dist/index.js +2111 -525
  17. package/plugin/dist/index.js.map +1 -1
  18. package/plugin/dist/{observations-Ch0nc47i.d.mts → observations-CorAAc1A.d.mts} +23 -1
  19. package/plugin/dist/observations-CorAAc1A.d.mts.map +1 -0
  20. package/plugin/dist/{tool-registry-CZ3mJ4iR.mjs → tool-registry-D8un_AcG.mjs} +932 -13
  21. package/plugin/dist/tool-registry-D8un_AcG.mjs.map +1 -0
  22. package/plugin/hooks/hooks.json +6 -6
  23. package/plugin/laminark.db +0 -0
  24. package/plugin/package.json +17 -0
  25. package/plugin/scripts/README.md +19 -1
  26. package/plugin/scripts/bump-version.sh +24 -19
  27. package/plugin/scripts/dev-sync.sh +58 -0
  28. package/plugin/scripts/ensure-deps.sh +5 -2
  29. package/plugin/scripts/install.sh +115 -39
  30. package/plugin/scripts/local-install.sh +93 -58
  31. package/plugin/scripts/uninstall.sh +76 -38
  32. package/plugin/scripts/update.sh +20 -69
  33. package/plugin/scripts/verify-install.sh +69 -25
  34. package/plugin/ui/activity.js +12 -0
  35. package/plugin/ui/app.js +24 -54
  36. package/plugin/ui/graph.js +413 -186
  37. package/plugin/ui/help/activity-feed.png +0 -0
  38. package/plugin/ui/help/analysis-panel.png +0 -0
  39. package/plugin/ui/help/graph-toolbar.png +0 -0
  40. package/plugin/ui/help/graph-view.png +0 -0
  41. package/plugin/ui/help/settings.png +0 -0
  42. package/plugin/ui/help/timeline.png +0 -0
  43. package/plugin/ui/help.js +876 -172
  44. package/plugin/ui/index.html +506 -242
  45. package/plugin/ui/settings.js +781 -17
  46. package/plugin/ui/styles.css +990 -44
  47. package/plugin/ui/timeline.js +2 -2
  48. package/plugin/ui/tools.js +826 -0
  49. package/.claude-plugin/marketplace.json +0 -15
  50. package/plugin/dist/observations-Ch0nc47i.d.mts.map +0 -1
  51. package/plugin/dist/tool-registry-CZ3mJ4iR.mjs.map +0 -1
  52. package/plugin/scripts/setup-tmpdir.sh +0 -65
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
- # Uninstall Laminark plugin with optional data cleanup
2
+ # Uninstall Laminark: remove MCP server, hooks, and npm package
3
3
 
4
4
  set -e
5
5
 
@@ -9,20 +9,24 @@ echo ""
9
9
 
10
10
  # Check if claude CLI is available
11
11
  if ! command -v claude &> /dev/null; then
12
- echo "Error: claude CLI not found"
13
- echo "Please install Claude Code first: https://claude.com/claude-code"
14
- exit 1
12
+ echo "Warning: claude CLI not found, skipping MCP/hook cleanup"
13
+ SKIP_CLAUDE=true
15
14
  fi
16
15
 
17
- # Check if plugin is installed
18
- if ! claude plugin list 2>/dev/null | grep -q "laminark"; then
19
- echo "Laminark plugin is not installed."
20
- exit 0
16
+ # Check what's installed
17
+ NPM_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
18
+ if [ -n "$NPM_VERSION" ]; then
19
+ echo "npm package: v$NPM_VERSION"
20
+ fi
21
+
22
+ # Check MCP registration
23
+ if [ "$SKIP_CLAUDE" != "true" ]; then
24
+ if claude mcp list 2>/dev/null | grep -q "laminark"; then
25
+ echo "MCP server: registered"
26
+ MCP_REGISTERED=true
27
+ fi
21
28
  fi
22
29
 
23
- # Get current version
24
- CURRENT_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
25
- echo "Currently installed: laminark v$CURRENT_VERSION"
26
30
  echo ""
27
31
 
28
32
  # Ask for confirmation
@@ -33,42 +37,76 @@ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
33
37
  exit 0
34
38
  fi
35
39
 
36
- # Remove the plugin
37
- echo "Removing plugin..."
38
- claude plugin remove laminark
39
- echo " Plugin removed"
40
+ # Step 1: Remove MCP server
41
+ if [ "$MCP_REGISTERED" = "true" ]; then
42
+ echo ""
43
+ echo "Removing MCP server..."
44
+ claude mcp remove laminark -s user 2>/dev/null || true
45
+ echo "✓ MCP server removed"
46
+ fi
40
47
 
41
- # Ask about data cleanup
48
+ # Step 2: Remove hooks from settings.json
49
+ echo ""
50
+ echo "Removing hooks from settings..."
51
+ SETTINGS_FILE="${CLAUDE_HOME:-$HOME/.claude}/settings.json"
52
+
53
+ if [ -f "$SETTINGS_FILE" ]; then
54
+ node -e '
55
+ const fs = require("fs");
56
+ const settingsPath = process.argv[1];
57
+
58
+ const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
59
+
60
+ if (settings.hooks) {
61
+ for (const [event, entries] of Object.entries(settings.hooks)) {
62
+ settings.hooks[event] = entries.filter(entry =>
63
+ !(entry.hooks && entry.hooks.some(h => h.command && h.command.includes("laminark")))
64
+ );
65
+ // Remove empty arrays
66
+ if (settings.hooks[event].length === 0) {
67
+ delete settings.hooks[event];
68
+ }
69
+ }
70
+ // Remove empty hooks object
71
+ if (Object.keys(settings.hooks).length === 0) {
72
+ delete settings.hooks;
73
+ }
74
+ }
75
+
76
+ // Remove laminark from enabledPlugins if present
77
+ if (settings.enabledPlugins) {
78
+ for (const key of Object.keys(settings.enabledPlugins)) {
79
+ if (key.includes("laminark")) {
80
+ delete settings.enabledPlugins[key];
81
+ }
82
+ }
83
+ }
84
+
85
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
86
+ ' "$SETTINGS_FILE"
87
+ echo "✓ Hooks removed"
88
+ fi
89
+
90
+ # Step 3: Uninstall npm package
91
+ if [ -n "$NPM_VERSION" ]; then
92
+ echo ""
93
+ echo "Uninstalling npm package..."
94
+ npm uninstall -g laminark
95
+ echo "✓ npm package removed"
96
+ fi
97
+
98
+ # Step 4: Optional data cleanup
42
99
  echo ""
43
100
  echo "Data cleanup options:"
44
101
  echo " 1. Keep all data (can reinstall later without losing memories)"
45
- echo " 2. Remove plugin cache only (keeps user data at ~/.laminark/)"
46
- echo " 3. Remove everything (plugin cache + all memories and data)"
102
+ echo " 2. Remove everything (all memories and data)"
47
103
  echo ""
48
- read -p "Choose option (1-3, default=1): " -n 1 -r CLEANUP_OPTION
104
+ read -p "Choose option (1-2, default=1): " -n 1 -r CLEANUP_OPTION
49
105
  echo ""
50
106
 
51
107
  case $CLEANUP_OPTION in
52
108
  2)
53
- echo "Removing plugin cache..."
54
- CACHE_DIR="${CLAUDE_HOME:-$HOME/.claude}/plugins/cache/laminark"
55
- if [ -d "$CACHE_DIR" ]; then
56
- rm -rf "$CACHE_DIR"
57
- echo "✓ Plugin cache removed: $CACHE_DIR"
58
- else
59
- echo " No cache directory found"
60
- fi
61
- ;;
62
- 3)
63
- echo "Removing all data..."
64
- CACHE_DIR="${CLAUDE_HOME:-$HOME/.claude}/plugins/cache/laminark"
65
109
  DATA_DIR="$HOME/.laminark"
66
-
67
- if [ -d "$CACHE_DIR" ]; then
68
- rm -rf "$CACHE_DIR"
69
- echo "✓ Plugin cache removed: $CACHE_DIR"
70
- fi
71
-
72
110
  if [ -d "$DATA_DIR" ]; then
73
111
  echo ""
74
112
  echo "WARNING: This will delete all your memories and observations!"
@@ -90,6 +128,6 @@ esac
90
128
  echo ""
91
129
  echo "✓ Uninstall complete!"
92
130
  echo ""
93
- echo "To reinstall: ./scripts/local-install.sh or ./scripts/install.sh"
131
+ echo "To reinstall: npm install -g laminark && ./plugin/scripts/install.sh"
94
132
 
95
133
  exit 0
@@ -1,88 +1,39 @@
1
1
  #!/bin/bash
2
- # Update Laminark plugin to the latest version
2
+ # Update Laminark to the latest version via npm
3
3
 
4
4
  set -e
5
5
 
6
- echo "Laminark Update Checker"
7
- echo "======================="
6
+ echo "Laminark Updater"
7
+ echo "================"
8
8
  echo ""
9
9
 
10
- # Check if claude CLI is available
11
- if ! command -v claude &> /dev/null; then
12
- echo "Error: claude CLI not found"
13
- echo "Please install Claude Code first: https://claude.com/claude-code"
10
+ # Check if npm is available
11
+ if ! command -v npm &> /dev/null; then
12
+ echo "Error: npm not found"
14
13
  exit 1
15
14
  fi
16
15
 
17
- # Check if plugin is installed
18
- if ! claude plugin list 2>/dev/null | grep -q "laminark"; then
19
- echo "Laminark is not installed."
20
- echo "Run ./scripts/install.sh to install it."
16
+ # Check if installed
17
+ CURRENT_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
18
+ if [ -z "$CURRENT_VERSION" ]; then
19
+ echo "Laminark is not installed globally."
20
+ echo "Run: ./plugin/scripts/install.sh"
21
21
  exit 1
22
22
  fi
23
23
 
24
- # Get current version
25
- CURRENT_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
26
24
  echo "Currently installed: v$CURRENT_VERSION"
27
-
28
- # Check for updates (try to get latest version from GitHub)
29
- echo "Checking for updates..."
30
- LATEST_VERSION=$(curl -fsSL https://api.github.com/repos/NoobyNull/Laminark/releases/latest 2>/dev/null | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/' || echo "")
31
-
32
- if [ -z "$LATEST_VERSION" ]; then
33
- echo "Warning: Could not check for updates (GitHub API unavailable)"
34
- echo ""
35
- read -p "Force reinstall anyway? (y/N): " -n 1 -r
36
- echo ""
37
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
38
- echo "Update cancelled."
39
- exit 0
40
- fi
41
- FORCE_UPDATE=true
42
- else
43
- echo "Latest available: v$LATEST_VERSION"
44
- echo ""
45
-
46
- # Compare versions
47
- if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
48
- echo "You already have the latest version!"
49
- echo ""
50
- read -p "Reinstall anyway? (y/N): " -n 1 -r
51
- echo ""
52
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
53
- echo "Update cancelled."
54
- exit 0
55
- fi
56
- fi
57
- fi
58
-
59
- # Set up TMPDIR to avoid EXDEV errors
60
- CLAUDE_DIR="${CLAUDE_HOME:-$HOME/.claude}"
61
- SAFE_TMP="$CLAUDE_DIR/tmp"
62
- mkdir -p "$SAFE_TMP"
63
-
64
- # Reinstall the plugin
65
25
  echo ""
66
- echo "Updating Laminark..."
67
- TMPDIR="$SAFE_TMP" claude plugin remove laminark 2>/dev/null || true
68
- TMPDIR="$SAFE_TMP" claude plugin install laminark
69
- STATUS=$?
70
-
71
- # Clean up
72
- rm -rf "$SAFE_TMP"
26
+ echo "Updating..."
27
+ npm update -g laminark
73
28
 
74
- if [ $STATUS -eq 0 ]; then
75
- NEW_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
76
- echo ""
77
- echo "✓ Laminark updated successfully!"
78
- echo " Previous version: v$CURRENT_VERSION"
79
- echo " Current version: v$NEW_VERSION"
80
- echo ""
81
- echo "Restart your Claude Code session for changes to take effect."
29
+ NEW_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "unknown")
30
+ echo ""
31
+ if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
32
+ echo "✓ Already at latest version: v$NEW_VERSION"
82
33
  else
83
- echo ""
84
- echo "✗ Update failed with exit code $STATUS"
85
- exit $STATUS
34
+ echo "✓ Updated: v$CURRENT_VERSION → v$NEW_VERSION"
86
35
  fi
36
+ echo ""
37
+ echo "Restart your Claude Code session for changes to take effect."
87
38
 
88
39
  exit 0
@@ -1,43 +1,87 @@
1
1
  #!/bin/bash
2
- # Verify Laminark plugin installation
3
- # Checks: plugin registered, enabled status, provides next steps
2
+ # Verify Laminark installation
3
+ # Checks: npm global package, MCP server, hooks in settings.json
4
4
 
5
5
  set -e
6
6
 
7
7
  echo "Checking Laminark installation..."
8
8
  echo ""
9
9
 
10
- # Check if claude CLI is available
10
+ ERRORS=0
11
+
12
+ # Check 1: npm global package
13
+ NPM_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
14
+ if [ -n "$NPM_VERSION" ]; then
15
+ echo "✓ npm package: v$NPM_VERSION"
16
+ else
17
+ # Check for npm link (dev install)
18
+ if command -v laminark-server &> /dev/null; then
19
+ echo "✓ laminark-server on PATH (linked)"
20
+ else
21
+ echo "✗ npm package not installed"
22
+ ERRORS=$((ERRORS + 1))
23
+ fi
24
+ fi
25
+
26
+ # Check 2: laminark-server binary
27
+ if command -v laminark-server &> /dev/null; then
28
+ echo "✓ laminark-server binary available"
29
+ else
30
+ echo "✗ laminark-server not found on PATH"
31
+ ERRORS=$((ERRORS + 1))
32
+ fi
33
+
34
+ # Check 3: laminark-hook binary
35
+ if command -v laminark-hook &> /dev/null; then
36
+ echo "✓ laminark-hook binary available"
37
+ else
38
+ echo "⚠ laminark-hook not on PATH (hooks may use direct node path)"
39
+ fi
40
+
41
+ # Check 4: Claude CLI
11
42
  if ! command -v claude &> /dev/null; then
12
- echo "✗ Error: claude CLI not found"
13
- echo " Please install Claude Code first: https://claude.com/claude-code"
14
- exit 1
43
+ echo "✗ claude CLI not found"
44
+ ERRORS=$((ERRORS + 1))
45
+ else
46
+ # Check 5: MCP server registration
47
+ if claude mcp list 2>/dev/null | grep -q "laminark"; then
48
+ echo "✓ MCP server registered"
49
+ else
50
+ echo "✗ MCP server not registered"
51
+ echo " Run: claude mcp add-json laminark '{\"command\":\"laminark-server\"}' -s user"
52
+ ERRORS=$((ERRORS + 1))
53
+ fi
15
54
  fi
16
55
 
17
- # Check if plugin is registered
18
- if claude plugin list 2>/dev/null | grep -q "laminark"; then
19
- echo " Plugin registered: laminark"
56
+ # Check 6: Hooks in settings.json
57
+ SETTINGS_FILE="${CLAUDE_HOME:-$HOME/.claude}/settings.json"
58
+ if [ -f "$SETTINGS_FILE" ]; then
59
+ if grep -q "laminark" "$SETTINGS_FILE"; then
60
+ echo "✓ Hooks configured in settings.json"
61
+ else
62
+ echo "✗ No laminark hooks in settings.json"
63
+ ERRORS=$((ERRORS + 1))
64
+ fi
20
65
  else
21
- echo "✗ Plugin not registered"
22
- echo " Please run: ./scripts/local-install.sh"
23
- exit 1
66
+ echo "✗ Settings file not found: $SETTINGS_FILE"
67
+ ERRORS=$((ERRORS + 1))
24
68
  fi
25
69
 
26
- # Check if plugin is enabled
27
- if claude plugin list 2>/dev/null | grep "laminark" | grep -q "enabled"; then
28
- echo " Plugin enabled"
70
+ # Check 7: Data directory
71
+ DATA_DIR="$HOME/.laminark"
72
+ if [ -d "$DATA_DIR" ]; then
73
+ echo "✓ Data directory exists: $DATA_DIR"
29
74
  else
30
- echo "⚠ Plugin registered but not enabled"
31
- echo " Run: claude plugin enable laminark"
75
+ echo "⚠ Data directory not yet created (will be created on first use)"
32
76
  fi
33
77
 
34
78
  echo ""
35
- echo "Installation verified successfully!"
36
- echo ""
37
- echo "Next steps:"
38
- echo " 1. Start a new Claude Code session"
39
- echo " 2. Check MCP tools with: /mcp"
40
- echo " 3. Check hooks with: /hooks"
41
- echo " 4. Try searching memories with: recall"
79
+ if [ $ERRORS -eq 0 ]; then
80
+ echo "Installation verified successfully!"
81
+ echo ""
82
+ echo "Start a new Claude Code session to use Laminark."
83
+ else
84
+ echo "Found $ERRORS issue(s). Run ./plugin/scripts/install.sh to fix."
85
+ fi
42
86
 
43
- exit 0
87
+ exit $ERRORS
@@ -122,6 +122,12 @@
122
122
  var config = EVENT_CONFIG[eventName];
123
123
  if (!config) return;
124
124
 
125
+ // Filter out events from other projects
126
+ if (detail.projectHash && window.laminarkState && window.laminarkState.currentProject &&
127
+ detail.projectHash !== window.laminarkState.currentProject) {
128
+ return;
129
+ }
130
+
125
131
  var item = {
126
132
  icon: config.icon,
127
133
  label: config.label,
@@ -175,6 +181,12 @@
175
181
  });
176
182
  });
177
183
 
184
+ // Clear feed when project changes
185
+ var projectSelect = document.getElementById('project-selector');
186
+ if (projectSelect) {
187
+ projectSelect.addEventListener('change', clearFeed);
188
+ }
189
+
178
190
  renderFeed();
179
191
  }
180
192
 
package/plugin/ui/app.js CHANGED
@@ -14,6 +14,7 @@ window.laminarkState = {
14
14
  timeline: null,
15
15
  graphInitialized: false,
16
16
  timelineInitialized: false,
17
+ toolsInitialized: false,
17
18
  currentProject: null,
18
19
  };
19
20
 
@@ -225,52 +226,30 @@ function connectSSE() {
225
226
  recordEventReceived();
226
227
  });
227
228
 
229
+ // Helper: dispatch SSE events that belong to the currently selected project.
230
+ // Events with a mismatched projectHash are dropped; events without projectHash
231
+ // are allowed through (server may not always tag them, e.g. older builds).
232
+ function dispatchIfCurrentProject(eventName, data) {
233
+ if (data.projectHash && data.projectHash !== window.laminarkState.currentProject) return;
234
+ document.dispatchEvent(new CustomEvent(eventName, { detail: data }));
235
+ }
236
+
228
237
  eventSource.addEventListener('new_observation', function (e) {
229
238
  var data = JSON.parse(e.data);
230
239
  recordEventReceived();
231
- document.dispatchEvent(new CustomEvent('laminark:new_observation', { detail: data }));
240
+ dispatchIfCurrentProject('laminark:new_observation', data);
232
241
  });
233
242
 
234
243
  eventSource.addEventListener('entity_updated', function (e) {
235
244
  var data = JSON.parse(e.data);
236
245
  recordEventReceived();
237
- document.dispatchEvent(new CustomEvent('laminark:entity_updated', { detail: data }));
246
+ dispatchIfCurrentProject('laminark:entity_updated', data);
238
247
  });
239
248
 
240
249
  eventSource.addEventListener('topic_shift', function (e) {
241
250
  var data = JSON.parse(e.data);
242
251
  recordEventReceived();
243
- document.dispatchEvent(new CustomEvent('laminark:topic_shift', { detail: data }));
244
- });
245
-
246
- eventSource.addEventListener('session_start', function (e) {
247
- var data = JSON.parse(e.data);
248
- recordEventReceived();
249
- document.dispatchEvent(new CustomEvent('laminark:session_start', { detail: data }));
250
- });
251
-
252
- eventSource.addEventListener('session_end', function (e) {
253
- var data = JSON.parse(e.data);
254
- recordEventReceived();
255
- document.dispatchEvent(new CustomEvent('laminark:session_end', { detail: data }));
256
- });
257
-
258
- eventSource.addEventListener('path_started', function (e) {
259
- var data = JSON.parse(e.data);
260
- recordEventReceived();
261
- document.dispatchEvent(new CustomEvent('laminark:path_started', { detail: data }));
262
- });
263
-
264
- eventSource.addEventListener('path_waypoint', function (e) {
265
- var data = JSON.parse(e.data);
266
- recordEventReceived();
267
- document.dispatchEvent(new CustomEvent('laminark:path_waypoint', { detail: data }));
268
- });
269
-
270
- eventSource.addEventListener('path_resolved', function (e) {
271
- var data = JSON.parse(e.data);
272
- recordEventReceived();
273
- document.dispatchEvent(new CustomEvent('laminark:path_resolved', { detail: data }));
252
+ dispatchIfCurrentProject('laminark:topic_shift', data);
274
253
  });
275
254
 
276
255
  eventSource.onerror = function () {
@@ -319,6 +298,10 @@ async function initProjectSelector() {
319
298
 
320
299
  select.addEventListener('change', function () {
321
300
  window.laminarkState.currentProject = select.value;
301
+ // Clear any pending batch updates from the previous project
302
+ if (window.laminarkGraph && window.laminarkGraph.clearBatchQueue) {
303
+ window.laminarkGraph.clearBatchQueue();
304
+ }
322
305
  // Reload all data for the new project
323
306
  if (window.laminarkGraph && window.laminarkState.graphInitialized) {
324
307
  window.laminarkGraph.loadGraphData();
@@ -383,6 +366,11 @@ function initNavigation() {
383
366
  window.laminarkGraph.loadGraphData();
384
367
  window.laminarkState.graphInitialized = true;
385
368
  }
369
+ } else if (targetView === 'tools-view' && !window.laminarkState.toolsInitialized) {
370
+ if (window.laminarkTools) {
371
+ window.laminarkTools.initTools('tools-view');
372
+ window.laminarkState.toolsInitialized = true;
373
+ }
386
374
  }
387
375
  });
388
376
  });
@@ -1481,7 +1469,8 @@ document.addEventListener('DOMContentLoaded', async function () {
1481
1469
  document.addEventListener('laminark:entity_updated', function (e) {
1482
1470
  if (!window.laminarkGraph) return;
1483
1471
  var data = e.detail;
1484
- if (data && data.id) {
1472
+ // Only add entities belonging to the currently selected project
1473
+ if (data && data.id && data.projectHash && data.projectHash === window.laminarkState.currentProject) {
1485
1474
  window.laminarkGraph.queueBatchUpdate({
1486
1475
  type: 'addNode',
1487
1476
  data: {
@@ -1496,32 +1485,13 @@ document.addEventListener('DOMContentLoaded', async function () {
1496
1485
  });
1497
1486
 
1498
1487
  document.addEventListener('laminark:new_observation', function () {
1499
- // Refresh observation counts by reloading graph data
1488
+ // Refresh observation counts by reloading graph data (already project-filtered at SSE dispatch)
1500
1489
  if (window.laminarkGraph) {
1501
1490
  var filters = getActiveFilters();
1502
1491
  window.laminarkGraph.loadGraphData(filters ? { type: filters.join(',') } : undefined);
1503
1492
  }
1504
1493
  });
1505
1494
 
1506
- // Path overlay event handlers (Plan 02 adds the graph overlay functions)
1507
- document.addEventListener('laminark:path_started', function (e) {
1508
- if (window.laminarkGraph && window.laminarkGraph.addPathOverlay) {
1509
- window.laminarkGraph.addPathOverlay(e.detail);
1510
- }
1511
- });
1512
-
1513
- document.addEventListener('laminark:path_waypoint', function (e) {
1514
- if (window.laminarkGraph && window.laminarkGraph.updatePathOverlay) {
1515
- window.laminarkGraph.updatePathOverlay(e.detail);
1516
- }
1517
- });
1518
-
1519
- document.addEventListener('laminark:path_resolved', function (e) {
1520
- if (window.laminarkGraph && window.laminarkGraph.resolvePathOverlay) {
1521
- window.laminarkGraph.resolvePathOverlay(e.detail);
1522
- }
1523
- });
1524
-
1525
1495
  // Filter change handler for graph (legacy listener)
1526
1496
  document.addEventListener('laminark:filter_change', function () {
1527
1497
  // Filter changes now handled directly in initFilters via graph.filterByType/resetFilters