synabun 1.3.0

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 (187) hide show
  1. package/CHANGELOG.md +665 -0
  2. package/LICENSE +191 -0
  3. package/README.md +853 -0
  4. package/hooks/claude-code/post-plan.mjs +391 -0
  5. package/hooks/claude-code/post-remember.mjs +239 -0
  6. package/hooks/claude-code/pre-compact.mjs +241 -0
  7. package/hooks/claude-code/pre-websearch.mjs +90 -0
  8. package/hooks/claude-code/prompt-submit.mjs +861 -0
  9. package/hooks/claude-code/session-start.mjs +494 -0
  10. package/hooks/claude-code/shared.mjs +368 -0
  11. package/hooks/claude-code/stop.mjs +646 -0
  12. package/hooks/claude-code/test-user-learning.mjs +531 -0
  13. package/mcp-server/package.json +38 -0
  14. package/mcp-server/run.mjs +10 -0
  15. package/mcp-server/src/config.ts +70 -0
  16. package/mcp-server/src/http.ts +93 -0
  17. package/mcp-server/src/index.ts +203 -0
  18. package/mcp-server/src/preload-http.ts +25 -0
  19. package/mcp-server/src/preload.ts +29 -0
  20. package/mcp-server/src/scripts/migrate-qdrant-to-sqlite.ts +506 -0
  21. package/mcp-server/src/services/categories.ts +429 -0
  22. package/mcp-server/src/services/discord.ts +702 -0
  23. package/mcp-server/src/services/file-checksums.ts +33 -0
  24. package/mcp-server/src/services/local-embeddings.ts +77 -0
  25. package/mcp-server/src/services/neural-interface.ts +344 -0
  26. package/mcp-server/src/services/sqlite.ts +823 -0
  27. package/mcp-server/src/tools/browser-advanced.ts +123 -0
  28. package/mcp-server/src/tools/browser-interact.ts +255 -0
  29. package/mcp-server/src/tools/browser-navigate.ts +77 -0
  30. package/mcp-server/src/tools/browser-observe.ts +1330 -0
  31. package/mcp-server/src/tools/browser.ts +107 -0
  32. package/mcp-server/src/tools/card-tools.ts +193 -0
  33. package/mcp-server/src/tools/card.ts +22 -0
  34. package/mcp-server/src/tools/category.ts +379 -0
  35. package/mcp-server/src/tools/discord-channel.ts +274 -0
  36. package/mcp-server/src/tools/discord-guild.ts +188 -0
  37. package/mcp-server/src/tools/discord-member.ts +158 -0
  38. package/mcp-server/src/tools/discord-message.ts +231 -0
  39. package/mcp-server/src/tools/discord-onboarding.ts +228 -0
  40. package/mcp-server/src/tools/discord-role.ts +209 -0
  41. package/mcp-server/src/tools/discord-thread.ts +110 -0
  42. package/mcp-server/src/tools/discord-webhook.ts +176 -0
  43. package/mcp-server/src/tools/discord.ts +40 -0
  44. package/mcp-server/src/tools/forget.ts +38 -0
  45. package/mcp-server/src/tools/git-tools.ts +141 -0
  46. package/mcp-server/src/tools/git.ts +13 -0
  47. package/mcp-server/src/tools/image-tools.ts +98 -0
  48. package/mcp-server/src/tools/image.ts +17 -0
  49. package/mcp-server/src/tools/leonardo-browser-tools.ts +281 -0
  50. package/mcp-server/src/tools/leonardo.ts +28 -0
  51. package/mcp-server/src/tools/loop.ts +348 -0
  52. package/mcp-server/src/tools/memories.ts +118 -0
  53. package/mcp-server/src/tools/recall.ts +323 -0
  54. package/mcp-server/src/tools/reflect.ts +145 -0
  55. package/mcp-server/src/tools/remember.ts +115 -0
  56. package/mcp-server/src/tools/response.ts +26 -0
  57. package/mcp-server/src/tools/restore.ts +34 -0
  58. package/mcp-server/src/tools/sync.ts +114 -0
  59. package/mcp-server/src/tools/tictactoe-tools.ts +98 -0
  60. package/mcp-server/src/tools/tictactoe.ts +13 -0
  61. package/mcp-server/src/tools/utils.ts +25 -0
  62. package/mcp-server/src/tools/whiteboard-tools.ts +260 -0
  63. package/mcp-server/src/tools/whiteboard.ts +22 -0
  64. package/mcp-server/src/tui.ts +940 -0
  65. package/mcp-server/src/types.ts +85 -0
  66. package/mcp-server/tsconfig.json +19 -0
  67. package/neural-interface/package.json +27 -0
  68. package/neural-interface/public/apple-touch-icon.png +0 -0
  69. package/neural-interface/public/category-logos/claude.svg +1 -0
  70. package/neural-interface/public/category-logos/gemini-color.svg +1 -0
  71. package/neural-interface/public/category-logos/openai.svg +1 -0
  72. package/neural-interface/public/category-logos/synabun.png +0 -0
  73. package/neural-interface/public/claude-chat.css +878 -0
  74. package/neural-interface/public/claude-chat.html +92 -0
  75. package/neural-interface/public/claude-chat.js +1168 -0
  76. package/neural-interface/public/favicon-16x16.png +0 -0
  77. package/neural-interface/public/favicon-32x32.png +0 -0
  78. package/neural-interface/public/gallery.svg +6 -0
  79. package/neural-interface/public/icon-192.png +0 -0
  80. package/neural-interface/public/icon-512.png +0 -0
  81. package/neural-interface/public/index-legacy.html +14677 -0
  82. package/neural-interface/public/index.html +212 -0
  83. package/neural-interface/public/index2d-legacy.html +8193 -0
  84. package/neural-interface/public/index2d.html +127 -0
  85. package/neural-interface/public/invite.html +351 -0
  86. package/neural-interface/public/leonardoai.svg +1 -0
  87. package/neural-interface/public/logo-synabun.png +0 -0
  88. package/neural-interface/public/logoHD.png +0 -0
  89. package/neural-interface/public/manifest.json +14 -0
  90. package/neural-interface/public/offline.html +299 -0
  91. package/neural-interface/public/onboarding.html +2335 -0
  92. package/neural-interface/public/openclaw-logo-text.png +0 -0
  93. package/neural-interface/public/pin-svgrepo-com.svg +25 -0
  94. package/neural-interface/public/sessionicon.svg +8 -0
  95. package/neural-interface/public/shared/ansi-parser.js +305 -0
  96. package/neural-interface/public/shared/api.js +1043 -0
  97. package/neural-interface/public/shared/colors.js +153 -0
  98. package/neural-interface/public/shared/constants.js +141 -0
  99. package/neural-interface/public/shared/html-shell.js +777 -0
  100. package/neural-interface/public/shared/html-term-renderer.js +1022 -0
  101. package/neural-interface/public/shared/i18n.js +147 -0
  102. package/neural-interface/public/shared/registry.js +82 -0
  103. package/neural-interface/public/shared/state.js +86 -0
  104. package/neural-interface/public/shared/storage.js +150 -0
  105. package/neural-interface/public/shared/styles.css +21212 -0
  106. package/neural-interface/public/shared/ui-automation-studio.js +3573 -0
  107. package/neural-interface/public/shared/ui-bookmarks.js +231 -0
  108. package/neural-interface/public/shared/ui-claude-panel.js +6333 -0
  109. package/neural-interface/public/shared/ui-command-runner.js +534 -0
  110. package/neural-interface/public/shared/ui-cost-widget.js +602 -0
  111. package/neural-interface/public/shared/ui-detail.js +1454 -0
  112. package/neural-interface/public/shared/ui-explorer.js +1356 -0
  113. package/neural-interface/public/shared/ui-file-explorer.js +2750 -0
  114. package/neural-interface/public/shared/ui-games.js +411 -0
  115. package/neural-interface/public/shared/ui-help.js +107 -0
  116. package/neural-interface/public/shared/ui-image-gallery.js +461 -0
  117. package/neural-interface/public/shared/ui-invite.js +519 -0
  118. package/neural-interface/public/shared/ui-keybinds.js +452 -0
  119. package/neural-interface/public/shared/ui-layouts.js +297 -0
  120. package/neural-interface/public/shared/ui-link.js +731 -0
  121. package/neural-interface/public/shared/ui-loading.js +255 -0
  122. package/neural-interface/public/shared/ui-menubar.js +499 -0
  123. package/neural-interface/public/shared/ui-multiselect.js +93 -0
  124. package/neural-interface/public/shared/ui-navbar.js +222 -0
  125. package/neural-interface/public/shared/ui-notifications.js +287 -0
  126. package/neural-interface/public/shared/ui-panels.js +309 -0
  127. package/neural-interface/public/shared/ui-resume.js +653 -0
  128. package/neural-interface/public/shared/ui-search.js +145 -0
  129. package/neural-interface/public/shared/ui-sessions.js +531 -0
  130. package/neural-interface/public/shared/ui-settings.js +5987 -0
  131. package/neural-interface/public/shared/ui-sidebar.js +1905 -0
  132. package/neural-interface/public/shared/ui-skills.js +2805 -0
  133. package/neural-interface/public/shared/ui-stats.js +38 -0
  134. package/neural-interface/public/shared/ui-sync.js +201 -0
  135. package/neural-interface/public/shared/ui-terminal.js +6385 -0
  136. package/neural-interface/public/shared/ui-tooltip.js +123 -0
  137. package/neural-interface/public/shared/ui-trash.js +439 -0
  138. package/neural-interface/public/shared/ui-tutorial-draw.js +875 -0
  139. package/neural-interface/public/shared/ui-tutorial-steps.js +2276 -0
  140. package/neural-interface/public/shared/ui-tutorial.js +1117 -0
  141. package/neural-interface/public/shared/ui-update.js +244 -0
  142. package/neural-interface/public/shared/ui-whiteboard.js +3262 -0
  143. package/neural-interface/public/shared/ui-workspaces.js +722 -0
  144. package/neural-interface/public/shared/utils.js +360 -0
  145. package/neural-interface/public/shared/vterm-buffer.js +1102 -0
  146. package/neural-interface/public/sw.js +52 -0
  147. package/neural-interface/public/synabun.png +0 -0
  148. package/neural-interface/public/toolbar-album.svg +8 -0
  149. package/neural-interface/public/toolbar-question.svg +6 -0
  150. package/neural-interface/public/toolbar-sessions.svg +6 -0
  151. package/neural-interface/public/variant/2d/background.js +113 -0
  152. package/neural-interface/public/variant/2d/context-menu.js +133 -0
  153. package/neural-interface/public/variant/2d/gfx.js +45 -0
  154. package/neural-interface/public/variant/2d/graph.js +1635 -0
  155. package/neural-interface/public/variant/2d/hulls.js +207 -0
  156. package/neural-interface/public/variant/2d/lasso.js +135 -0
  157. package/neural-interface/public/variant/2d/layout.js +594 -0
  158. package/neural-interface/public/variant/2d/main.js +521 -0
  159. package/neural-interface/public/variant/2d/minimap.js +312 -0
  160. package/neural-interface/public/variant/2d/settings-gfx.js +98 -0
  161. package/neural-interface/public/variant/3d/background.js +884 -0
  162. package/neural-interface/public/variant/3d/camera.js +661 -0
  163. package/neural-interface/public/variant/3d/gfx.js +116 -0
  164. package/neural-interface/public/variant/3d/graph.js +2399 -0
  165. package/neural-interface/public/variant/3d/main.js +500 -0
  166. package/neural-interface/public/variant/3d/settings-gfx.js +228 -0
  167. package/neural-interface/scripts/rebuild-pty.js +100 -0
  168. package/neural-interface/server.js +15000 -0
  169. package/neural-interface/templates/CLAUDE-template.md +211 -0
  170. package/package.json +53 -0
  171. package/postinstall.js +135 -0
  172. package/setup.js +260 -0
  173. package/skills/leonardo/SKILL.md +159 -0
  174. package/skills/leonardo/icon.svg +1 -0
  175. package/skills/leonardo/modules/browser-guide.md +378 -0
  176. package/skills/leonardo/modules/image-prompter.md +277 -0
  177. package/skills/leonardo/modules/model-advisor.md +100 -0
  178. package/skills/leonardo/modules/prompt-library.md +110 -0
  179. package/skills/leonardo/modules/style-guide.md +186 -0
  180. package/skills/leonardo/modules/video-prompter.md +311 -0
  181. package/skills/synabun/SKILL.md +185 -0
  182. package/skills/synabun/icon.png +0 -0
  183. package/skills/synabun/modules/audit.md +374 -0
  184. package/skills/synabun/modules/changelog.md +194 -0
  185. package/skills/synabun/modules/idea.md +144 -0
  186. package/skills/synabun/modules/memorize.md +188 -0
  187. package/skills/synabun/synabunicon.png +0 -0
@@ -0,0 +1,500 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — 3D Variant Entry Point
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Registers the 3D variant, imports all shared & variant modules,
6
+ // wires event listeners, and boots the application.
7
+
8
+ // ── Storage (self-hydrating — importing it populates the cache) ──
9
+ import { storage } from '../../shared/storage.js';
10
+
11
+ // ── Shared foundation ──
12
+ import { state, emit, on } from '../../shared/state.js';
13
+ import { registerVariant, registerMenuItem, registerHelpSection } from '../../shared/registry.js';
14
+ import { fetchMemories } from '../../shared/api.js';
15
+ import { normalizeNodes } from '../../shared/utils.js';
16
+ import { injectSharedHTML } from '../../shared/html-shell.js';
17
+ import { KEYS } from '../../shared/constants.js';
18
+ import { initI18n, t } from '../../shared/i18n.js';
19
+
20
+ // ── Shared UI modules (side-effect: each registers its own event listeners) ──
21
+ import { initTooltip } from '../../shared/ui-tooltip.js';
22
+ import { initPanelSystem, initPinToggle, clampPanelsToViewport } from '../../shared/ui-panels.js';
23
+ import { initLoading, showLoadingError, hideLoading } from '../../shared/ui-loading.js';
24
+ import { initNavbar } from '../../shared/ui-navbar.js';
25
+ import { initMenubar } from '../../shared/ui-menubar.js';
26
+ import { initSearch } from '../../shared/ui-search.js';
27
+ import { buildCategorySidebar, initSidebar, preloadCategoryLogos, loadCategories } from '../../shared/ui-sidebar.js';
28
+ import { openMemoryCard, restoreOpenCards, initDetailPanel, setDetailCallbacks } from '../../shared/ui-detail.js';
29
+ import { initSettings, restoreInterfaceConfig, restoreSkin, loadIfaceConfig } from '../../shared/ui-settings.js';
30
+ import { initTrash } from '../../shared/ui-trash.js';
31
+ import { initBookmarks } from '../../shared/ui-bookmarks.js';
32
+ import { initResume } from '../../shared/ui-resume.js';
33
+ import { initLayouts, registerBuiltinPresets } from '../../shared/ui-layouts.js';
34
+ import { initHelp } from '../../shared/ui-help.js';
35
+ import { initMultiSelect } from '../../shared/ui-multiselect.js';
36
+ import { updateStats, initStats } from '../../shared/ui-stats.js';
37
+ import { initExplorer } from '../../shared/ui-explorer.js';
38
+ import { initFileExplorer } from '../../shared/ui-file-explorer.js';
39
+ import { initSkillsStudio } from '../../shared/ui-skills.js';
40
+ import { initTerminal } from '../../shared/ui-terminal.js';
41
+ import { initLink } from '../../shared/ui-link.js';
42
+ import { initWhiteboard } from '../../shared/ui-whiteboard.js';
43
+ import { initCostWidget } from '../../shared/ui-cost-widget.js';
44
+ import { initGames, clearGameOnLoad } from '../../shared/ui-games.js';
45
+ import { initWorkspaces } from '../../shared/ui-workspaces.js';
46
+ import { initInvite } from '../../shared/ui-invite.js';
47
+ import { initSync } from '../../shared/ui-sync.js';
48
+ import { initKeybinds } from '../../shared/ui-keybinds.js';
49
+ import { initTutorial } from '../../shared/ui-tutorial.js';
50
+ import { initImageGallery } from '../../shared/ui-image-gallery.js';
51
+
52
+ // ── 3D variant modules ──
53
+ import { gfx } from './gfx.js';
54
+ import { setGraphicsHooks } from './settings-gfx.js';
55
+ import { initAutomationStudio } from '../../shared/ui-automation-studio.js';
56
+ import { initCommandRunner } from '../../shared/ui-command-runner.js';
57
+ import { initCamera, updateCameraMovement, animateCameraToNode, frameCameraToExtent, saveCameraState, restoreCameraState, pauseCamera, resumeCamera } from './camera.js';
58
+ import { applyFloorStyle, applyBgTheme, animateBackground } from './background.js';
59
+ import {
60
+ initGraph, getGraph, getBloomPass, applyGraphData,
61
+ preloadCategoryLogos as preloadGraphLogos,
62
+ applyLinkVisibility, setLinkMode, setLinkTypeFilter,
63
+ navigateToNode, scheduleGraphRemoval, cancelScheduledRemoval,
64
+ saveNodePositions, clearSavedPositions, resetLayout,
65
+ setBloomParams, setBloomEnabled, stopAnimation, startAnimation,
66
+ pauseInteraction, resumeInteraction,
67
+ } from './graph.js';
68
+
69
+
70
+ // ═══════════════════════════════════════════
71
+ // 1. REGISTER VARIANT
72
+ // ═══════════════════════════════════════════
73
+
74
+ registerVariant({
75
+ variant: '3d',
76
+ capabilities: ['camera-hud', 'controls-panel', 'bloom', 'floor-effects', 'background-theme'],
77
+ });
78
+
79
+
80
+ // ═══════════════════════════════════════════
81
+ // 2. REGISTER VARIANT-SPECIFIC MENU ITEMS
82
+ // ═══════════════════════════════════════════
83
+
84
+ registerMenuItem({
85
+ menu: 'view',
86
+ order: 25,
87
+ type: 'toggle',
88
+ id: 'menu-3d-controls',
89
+ label: '3D Controls',
90
+ init: (el) => {
91
+ el.addEventListener('click', () => {
92
+ const panel = document.getElementById('controls-panel');
93
+ if (panel) panel.classList.toggle('visible');
94
+ el.classList.toggle('active', panel?.classList.contains('visible'));
95
+ });
96
+ },
97
+ });
98
+
99
+
100
+ // ═══════════════════════════════════════════
101
+ // 3. REGISTER VARIANT HELP SECTION
102
+ // ═══════════════════════════════════════════
103
+
104
+ registerHelpSection({
105
+ order: 50,
106
+ html: `<div class="help-section">
107
+ <div class="help-section-title">3D Navigation</div>
108
+ <div class="help-row"><div class="help-keys"><span class="help-key">W</span><span class="help-key">A</span><span class="help-key">S</span><span class="help-key">D</span></div><span class="help-desc">Move camera</span></div>
109
+ <div class="help-row"><div class="help-keys"><span class="help-key">Q</span><span class="help-key">E</span></div><span class="help-desc">Move camera down / up</span></div>
110
+ <div class="help-row"><div class="help-keys"><span class="help-key">Shift</span></div><span class="help-desc">Boost speed (hold)</span></div>
111
+ <div class="help-row"><div class="help-keys"><span class="help-key">Mouse</span><span class="help-key">+</span><span class="help-key">W</span></div><span class="help-desc">Fly towards look direction</span></div>
112
+ <div class="help-row"><div class="help-keys"><span class="help-key">Drag</span></div><span class="help-desc">Orbit camera</span></div>
113
+ <div class="help-row"><div class="help-keys"><span class="help-key">Scroll</span></div><span class="help-desc">Zoom in / out</span></div>
114
+ </div>`,
115
+ });
116
+
117
+
118
+ // ═══════════════════════════════════════════
119
+ // 4. LOAD TRANSLATIONS & INJECT SHARED HTML
120
+ // ═══════════════════════════════════════════
121
+
122
+ await initI18n();
123
+ injectSharedHTML();
124
+
125
+ // Provide hooks to the 3D graphics settings tab
126
+ setGraphicsHooks({
127
+ applyBgTheme: (theme) => {
128
+ const g = getGraph();
129
+ const bloom = getBloomPass();
130
+ if (g) applyBgTheme(g, bloom);
131
+ },
132
+ applyFloorStyle: (style) => {
133
+ const g = getGraph();
134
+ if (g) applyFloorStyle(style, g);
135
+ },
136
+ getGraph,
137
+ setBloomEnabled,
138
+ });
139
+
140
+
141
+ // ═══════════════════════════════════════════
142
+ // 5. WIRE EVENT BUS — connect shared events to variant actions
143
+ // ═══════════════════════════════════════════
144
+
145
+ // When shared UI emits graph:navigate, move camera to node
146
+ on('graph:navigate', ({ node, zoom }) => {
147
+ if (node) navigateToNode(node, { zoom });
148
+ });
149
+
150
+ // When shared UI requests data reload (e.g. after OpenClaw bridge sync)
151
+ on('data:reload', async () => {
152
+ try {
153
+ const needLinks = state.linkMode !== 'off';
154
+ const res = await fetch(`/api/memories${needLinks ? '' : '?links=false'}`);
155
+ if (!res.ok) return;
156
+ const data = await res.json();
157
+ state.allNodes = normalizeNodes(data.nodes);
158
+ state.allLinks = data.links;
159
+
160
+ await loadCategories();
161
+ // Preload logos into graph module's own map (sidebar has a separate one)
162
+ const _logoCats = Object.entries(state.categoryMetadata)
163
+ .filter(([, m]) => m.logo)
164
+ .map(([name, m]) => ({ name, logo: m.logo }));
165
+ preloadGraphLogos(_logoCats);
166
+
167
+ const presentCats = new Set(state.allNodes.map(n => n.payload.category));
168
+ state.activeCategories = new Set([...presentCats, ...state.allCategoryNames]);
169
+
170
+ buildCategorySidebar(presentCats);
171
+ applyGraphData();
172
+ updateStats();
173
+ } catch (err) {
174
+ console.error('data:reload failed:', err);
175
+ }
176
+ });
177
+
178
+ // When categories change, rebuild sidebar and refresh graph
179
+ on('categories-changed', () => {
180
+ // Re-preload logos in case a category logo was added/changed
181
+ const _lc = Object.entries(state.categoryMetadata)
182
+ .filter(([, m]) => m.logo)
183
+ .map(([name, m]) => ({ name, logo: m.logo }));
184
+ preloadGraphLogos(_lc);
185
+ applyGraphData();
186
+ });
187
+
188
+ // When search applies, refresh graph to show/hide nodes
189
+ on('search:apply', () => {
190
+ applyGraphData();
191
+ });
192
+
193
+ on('search:clear', () => {
194
+ applyGraphData();
195
+ });
196
+
197
+ // Link mode changes
198
+ on('link-mode-changed', (mode) => {
199
+ setLinkMode(mode);
200
+ });
201
+
202
+ on('link-type-changed', (filter) => {
203
+ setLinkTypeFilter(filter);
204
+ });
205
+
206
+ // Node selection — zoom camera + open detail card
207
+ on('node-selected', (node) => {
208
+ if (node) {
209
+ animateCameraToNode(node, { zoom: 'close' });
210
+ openMemoryCard(node);
211
+ }
212
+ });
213
+
214
+ // Graph refresh request (from settings sliders, etc.)
215
+ on('graph:refresh', () => {
216
+ applyGraphData();
217
+ });
218
+
219
+ // Per-frame WASD camera movement
220
+ on('camera-tick', () => {
221
+ updateCameraMovement();
222
+ });
223
+
224
+ // Animation tick — update background animations
225
+ on('animate-tick', ({ time, graph: g }) => {
226
+ animateBackground(time, g);
227
+ });
228
+
229
+ // When a category is removed and its nodes should disappear
230
+ on('category:schedule-removal', () => {
231
+ scheduleGraphRemoval();
232
+ });
233
+
234
+ on('category:cancel-removal', () => {
235
+ cancelScheduledRemoval();
236
+ });
237
+
238
+ // Layout commands
239
+ on('layout:reset', () => {
240
+ clearSavedPositions();
241
+ resetLayout();
242
+ });
243
+
244
+ on('layout:frame', (nodes) => {
245
+ frameCameraToExtent(nodes || state.allNodes);
246
+ });
247
+
248
+ // Stats update
249
+ on('stats-changed', () => {
250
+ updateStats();
251
+ });
252
+
253
+
254
+ // ═══════════════════════════════════════════
255
+ // 6. DETAIL PANEL CALLBACKS
256
+ // ═══════════════════════════════════════════
257
+
258
+ setDetailCallbacks({
259
+ navigateToNode: (node) => navigateToNode(node, { zoom: 'close' }),
260
+ refreshGraph: () => applyGraphData(),
261
+ scheduleRemoval: () => scheduleGraphRemoval(),
262
+ cancelRemoval: () => cancelScheduledRemoval(),
263
+ });
264
+
265
+
266
+ // ═══════════════════════════════════════════
267
+ // 7. BOOT SEQUENCE
268
+ // ═══════════════════════════════════════════
269
+
270
+ async function boot() {
271
+ try {
272
+ // Restore interface customization + active skin before anything renders
273
+ restoreInterfaceConfig();
274
+ restoreSkin();
275
+
276
+ // Pre-flight health check
277
+ try {
278
+ const healthRes = await fetch('/api/health');
279
+ const health = await healthRes.json();
280
+ if (!health.ok) {
281
+ const messages = {
282
+ db_missing: [t('loading.health.databaseUnreachable.title'), health.detail || t('loading.health.databaseUnreachable.sub')],
283
+ db_error: [t('loading.health.databaseUnreachable.title'), health.detail || t('loading.health.databaseUnreachable.sub')],
284
+ remote_unreachable: [t('loading.health.remoteUnreachable.title'), health.detail || t('loading.health.remoteUnreachable.sub')],
285
+ auth_error: [t('loading.health.authError.title'), health.detail || t('loading.health.authError.sub')],
286
+ };
287
+ const [title, sub] = messages[health.reason] || [t('loading.health.connectionError.title'), health.detail || t('loading.health.connectionError.sub')];
288
+ showLoadingError(title, sub, !!health.canAutoStart);
289
+ return;
290
+ }
291
+ } catch {
292
+ // /api/health failed — continue to try /api/memories
293
+ }
294
+
295
+ // Fetch all memories (skip expensive link computation — loaded on demand)
296
+ const res = await fetch('/api/memories?links=false');
297
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
298
+ const data = await res.json();
299
+
300
+ state.allNodes = normalizeNodes(data.nodes);
301
+ state.allLinks = data.links;
302
+
303
+ // Fetch category definitions
304
+ await loadCategories();
305
+ // Preload logos into graph module's own map (sidebar has a separate one)
306
+ const _logoCats = Object.entries(state.categoryMetadata)
307
+ .filter(([, m]) => m.logo)
308
+ .map(([name, m]) => ({ name, logo: m.logo }));
309
+ preloadGraphLogos(_logoCats);
310
+
311
+ // Discover all categories present
312
+ const presentCats = new Set(state.allNodes.map(n => n.payload.category));
313
+ state.activeCategories = new Set([...presentCats, ...state.allCategoryNames]);
314
+
315
+ // Build category sidebar
316
+ buildCategorySidebar(presentCats);
317
+
318
+ // Init the 3D graph (skip if visualization is disabled or already init'd by viz:toggle)
319
+ const container = document.getElementById('graph-container');
320
+ const vizEnabled = loadIfaceConfig().visualizationEnabled !== false;
321
+
322
+ if (vizEnabled && !getGraph()) {
323
+ initGraph(container, {
324
+ onApplyBgTheme: (theme) => {
325
+ const g = getGraph();
326
+ const bloom = getBloomPass();
327
+ if (g) applyBgTheme(g, bloom);
328
+ },
329
+ });
330
+
331
+ // Init camera controls
332
+ const g = getGraph();
333
+ if (g) initCamera(g);
334
+
335
+ // Apply floor style from saved config
336
+ if (g) applyFloorStyle(gfx.floorStyle || 'grid', g);
337
+ }
338
+
339
+ // Update stats
340
+ updateStats();
341
+
342
+ // Notify shared modules that data is ready
343
+ emit('data-loaded', data);
344
+
345
+ // Restore previously open memory cards (persisted positions)
346
+ restoreOpenCards();
347
+
348
+ // Check for cross-variant node switch
349
+ const switchNodeId = sessionStorage.getItem('neural-selected-node-switch');
350
+ if (switchNodeId) {
351
+ sessionStorage.removeItem('neural-selected-node-switch');
352
+ const switchNode = state.allNodes.find(n => n.id === switchNodeId);
353
+ if (switchNode) {
354
+ state.selectedNodeId = switchNodeId;
355
+ openMemoryCard(switchNode);
356
+ setTimeout(() => navigateToNode(switchNode, { zoom: 'close' }), 500);
357
+ }
358
+ }
359
+
360
+ // Fetch trash count
361
+ try { emit('trash:refresh'); } catch {}
362
+
363
+ // Fade out loading
364
+ hideLoading(400);
365
+
366
+ // Mark boot complete — viz:toggle handler can now respond to user toggles
367
+ _bootComplete = true;
368
+
369
+ } catch (err) {
370
+ console.error('Init error:', err);
371
+ const isNetworkError = err.message === 'Failed to fetch' || err.name === 'TypeError';
372
+ showLoadingError(
373
+ isNetworkError ? t('loading.serverOffline') : t('loading.connectionFailed'),
374
+ isNetworkError ? t('loading.serverNotRunning') : err.message,
375
+ false,
376
+ isNetworkError
377
+ );
378
+ }
379
+ }
380
+
381
+
382
+ // ═══════════════════════════════════════════
383
+ // 8. INIT ALL SHARED UI SYSTEMS
384
+ // ═══════════════════════════════════════════
385
+
386
+ initLoading({ onInit: boot });
387
+ initKeybinds(); // async — loads keybinds from server, installs central dispatcher
388
+ initTooltip();
389
+ initPanelSystem();
390
+ initPinToggle();
391
+ initNavbar();
392
+ initMenubar();
393
+ initSearch();
394
+ initSidebar();
395
+ initDetailPanel();
396
+ initSettings();
397
+ initTrash();
398
+ initBookmarks();
399
+ initResume();
400
+ initLayouts();
401
+ initWorkspaces();
402
+ initInvite();
403
+ initSync();
404
+ initHelp();
405
+ initMultiSelect();
406
+ initStats();
407
+ initExplorer();
408
+ initFileExplorer();
409
+ initSkillsStudio();
410
+ initAutomationStudio();
411
+ initImageGallery();
412
+ initCommandRunner();
413
+ initTerminal();
414
+ initLink();
415
+ clearGameOnLoad();
416
+ initWhiteboard();
417
+ initCostWidget();
418
+ initGames();
419
+ initTutorial();
420
+
421
+ // View switch handler
422
+ {
423
+ const switchBtn = document.querySelector('.view-toggle-btn:not(.active)');
424
+ if (switchBtn) {
425
+ switchBtn.addEventListener('click', (e) => {
426
+ e.preventDefault();
427
+ if (state.selectedNodeId) sessionStorage.setItem('neural-selected-node-switch', state.selectedNodeId);
428
+ window.location.href = switchBtn.getAttribute('href');
429
+ });
430
+ }
431
+ }
432
+
433
+ // Window resize handler
434
+ window.addEventListener('resize', () => {
435
+ clampPanelsToViewport();
436
+ });
437
+
438
+ // Visualization toggle — pause/resume 3D rendering
439
+ // Guard: ignore viz:toggle events emitted during boot (from restoreInterfaceConfig).
440
+ // Boot handles graph init itself; this handler is only for runtime user toggles.
441
+ let _bootComplete = false;
442
+ on('viz:toggle', (enabled) => {
443
+ if (!_bootComplete) return;
444
+ if (enabled) {
445
+ if (!getGraph()) {
446
+ // First-time init if graph was never created (was disabled at boot)
447
+ const container = document.getElementById('graph-container');
448
+ initGraph(container, {
449
+ onApplyBgTheme: () => {
450
+ const g = getGraph();
451
+ const bloom = getBloomPass();
452
+ if (g) applyBgTheme(g, bloom);
453
+ },
454
+ });
455
+ const g = getGraph();
456
+ if (g) initCamera(g);
457
+ if (g) applyFloorStyle(gfx.floorStyle || 'grid', g);
458
+ applyGraphData();
459
+ }
460
+ startAnimation();
461
+ } else {
462
+ stopAnimation();
463
+ }
464
+ });
465
+
466
+ // Focus mode isolation — zero-resource mode for 3D
467
+ on('focus:enter', () => {
468
+ state.hoveredNodeId = null;
469
+ document.body.style.cursor = 'default';
470
+ pauseInteraction();
471
+ pauseCamera();
472
+ });
473
+
474
+ on('focus:exit', () => {
475
+ resumeInteraction();
476
+ resumeCamera();
477
+ });
478
+
479
+ // Workspace scene snapshot (3D)
480
+ on('workspace:get-scene', (callback) => {
481
+ const graph = getGraph();
482
+ if (!graph) return callback({ nodePositions: {}, camera: null });
483
+ const gd = graph.graphData();
484
+ const positions = {};
485
+ for (const n of gd.nodes) {
486
+ if (n.x != null) positions[n.id] = { x: n.x, y: n.y, z: n.z };
487
+ }
488
+ callback({ nodePositions: positions, camera: saveCameraState() });
489
+ });
490
+
491
+ on('workspace:restore-scene', ({ nodePositions, camera }) => {
492
+ if (nodePositions && Object.keys(nodePositions).length > 0) {
493
+ storage.setItem(KEYS.NODE_POS_3D, JSON.stringify(nodePositions));
494
+ }
495
+ if (camera) restoreCameraState(camera, 1500);
496
+ applyGraphData();
497
+ });
498
+
499
+ // Boot
500
+ boot();