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,521 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — 2D Variant Entry Point
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Registers the 2D 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
+
15
+ import { injectSharedHTML } from '../../shared/html-shell.js';
16
+ import { KEYS } from '../../shared/constants.js';
17
+ import { normalizeNodes } from '../../shared/utils.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, 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 } 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, registerAction, getDisplayKey } from '../../shared/ui-keybinds.js';
49
+ import { initTutorial } from '../../shared/ui-tutorial.js';
50
+ import { initImageGallery } from '../../shared/ui-image-gallery.js';
51
+
52
+ // ── 2D variant modules ──
53
+ import { gfx, saveGfxConfig } from './gfx.js';
54
+ import './settings-gfx.js'; // side-effect: self-registers Graphics tab
55
+ import { initAutomationStudio } from '../../shared/ui-automation-studio.js';
56
+ import { initCommandRunner } from '../../shared/ui-command-runner.js';
57
+ import { stopBackground } from './background.js';
58
+ import { initMinimap, drawMinimap, toggleMinimap, isMinimapVisible, forceHideMinimap, restoreMinimap } from './minimap.js';
59
+ import { initLasso, clearLasso } from './lasso.js';
60
+ import { initContextMenu, hideContextMenu } from './context-menu.js';
61
+ import {
62
+ initGraph, getGraph, applyGraphData,
63
+ preloadCategoryLogos, scheduleGraphRemoval, cancelScheduledRemoval,
64
+ refreshGraph, reheatSimulation, getAllCards,
65
+ stopAnimation, startAnimation,
66
+ pauseInteraction, resumeInteraction,
67
+ } from './graph.js';
68
+
69
+
70
+ // ═══════════════════════════════════════════
71
+ // 1. REGISTER VARIANT
72
+ // ═══════════════════════════════════════════
73
+
74
+ registerVariant({
75
+ variant: '2d',
76
+ capabilities: ['minimap', 'lasso', 'context-menu', 'orbital-layout'],
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-region-glow',
89
+ label: 'Region Glow',
90
+ init: (el) => {
91
+ el.classList.toggle('active', gfx.regionGlowOpacity > 0);
92
+ el.addEventListener('click', () => {
93
+ if (gfx.regionGlowOpacity > 0) {
94
+ gfx.regionGlowOpacity = 0;
95
+ } else {
96
+ gfx.regionGlowOpacity = 0.05;
97
+ }
98
+ saveGfxConfig(gfx);
99
+ el.classList.toggle('active', gfx.regionGlowOpacity > 0);
100
+ });
101
+ },
102
+ });
103
+
104
+ registerMenuItem({
105
+ menu: 'view',
106
+ order: 26,
107
+ type: 'toggle',
108
+ id: 'menu-minimap',
109
+ label: 'Minimap',
110
+ shortcut: 'M',
111
+ init: (el) => {
112
+ // Set initial active state (minimap starts visible)
113
+ el.classList.add('active');
114
+
115
+ const doToggle = () => {
116
+ toggleMinimap();
117
+ el.classList.toggle('active', isMinimapVisible());
118
+ };
119
+
120
+ el.addEventListener('click', doToggle);
121
+
122
+ // Register keybind action so the central dispatcher can trigger it
123
+ registerAction('toggle-minimap', doToggle);
124
+ },
125
+ });
126
+
127
+
128
+ // ═══════════════════════════════════════════
129
+ // 3. REGISTER VARIANT HELP SECTION
130
+ // ═══════════════════════════════════════════
131
+
132
+ registerHelpSection({
133
+ order: 50,
134
+ html: `
135
+ <h4>2D Canvas Controls</h4>
136
+ <div class="help-key-row"><span class="help-key">Mouse Drag</span> Pan the canvas</div>
137
+ <div class="help-key-row"><span class="help-key">Scroll</span> Zoom in/out</div>
138
+ <div class="help-key-row"><span class="help-key">Click Card</span> Select &amp; open detail</div>
139
+ <div class="help-key-row"><span class="help-key">Click Category</span> Zoom to category</div>
140
+ <div class="help-key-row"><span class="help-key">Double-Click Card</span> Unpin card</div>
141
+ <div class="help-key-row"><span class="help-key">Double-Click BG</span> Zoom to fit all</div>
142
+ <div class="help-key-row"><span class="help-key">Right-Click Card</span> Context menu</div>
143
+ <div class="help-key-row"><span class="help-key">Shift + Drag</span> Lasso select</div>
144
+ <div class="help-key-row"><span class="help-key">Drag Card</span> Move &amp; pin card</div>
145
+ <div class="help-key-row"><span class="help-key">Drag Category</span> Move entire group</div>
146
+ `,
147
+ });
148
+
149
+
150
+ // ═══════════════════════════════════════════
151
+ // 4. LOAD TRANSLATIONS & INJECT SHARED HTML
152
+ // ═══════════════════════════════════════════
153
+
154
+ await initI18n();
155
+ injectSharedHTML();
156
+
157
+
158
+ // ═══════════════════════════════════════════
159
+ // 5. WIRE EVENT BUS — connect shared events to variant actions
160
+ // ═══════════════════════════════════════════
161
+
162
+ // When shared UI emits graph:navigate, center on node
163
+ on('graph:navigate', ({ node, zoom }) => {
164
+ const g = getGraph();
165
+ if (!node || !g) return;
166
+ const cards = getAllCards();
167
+ const card = cards.find(c => c.node.id === node.id);
168
+ if (card) {
169
+ g.centerAt(card.x, card.y, 500);
170
+ if (zoom === 'close') g.zoom(4, 500);
171
+ }
172
+ });
173
+
174
+ // Data reload (e.g. after OpenClaw bridge sync)
175
+ on('data:reload', async () => {
176
+ try {
177
+ await refreshGraph();
178
+ const presentCats = new Set(state.allNodes.map(n => n.payload.category));
179
+ buildCategorySidebar(presentCats);
180
+ updateStats();
181
+ } catch (err) {
182
+ console.error('data:reload failed:', err);
183
+ }
184
+ });
185
+
186
+ // Categories changed
187
+ on('categories-changed', () => {
188
+ applyGraphData();
189
+ });
190
+
191
+ // Search apply/clear
192
+ on('search:apply', () => {
193
+ // No layout recompute needed — just re-renders with dimming
194
+ });
195
+
196
+ on('search:clear', () => {
197
+ // No layout recompute needed
198
+ });
199
+
200
+ // Link mode changes — just triggers re-render (no API call needed)
201
+ on('link-mode-changed', () => {
202
+ // Render loop picks up state.linkMode automatically
203
+ });
204
+
205
+ on('link-type-changed', () => {
206
+ // Render loop picks up state.linkTypeFilter automatically
207
+ });
208
+
209
+ // Node selection — center camera on selected card + open detail card
210
+ on('node-selected', (node) => {
211
+ if (!node) return;
212
+ const g = getGraph();
213
+ if (g) {
214
+ const cards = getAllCards();
215
+ const card = cards.find(c => c.node.id === node.id);
216
+ if (card) {
217
+ g.centerAt(card.x, card.y, 500);
218
+ }
219
+ }
220
+ openMemoryCard(node);
221
+ });
222
+
223
+ // Graph refresh
224
+ on('graph:refresh', () => {
225
+ applyGraphData();
226
+ });
227
+
228
+ // Category removal scheduling
229
+ on('category:schedule-removal', () => {
230
+ scheduleGraphRemoval();
231
+ });
232
+
233
+ on('category:cancel-removal', () => {
234
+ cancelScheduledRemoval();
235
+ });
236
+
237
+ // Layout commands
238
+ on('layout:reset', () => {
239
+ reheatSimulation(); // clears saved positions + recomputes layout
240
+ });
241
+
242
+ on('layout:frame', () => {
243
+ const g = getGraph();
244
+ if (g) g.zoomToFit(400, 60);
245
+ });
246
+
247
+ // Stats update
248
+ on('stats-changed', () => {
249
+ updateStats();
250
+ });
251
+
252
+ // Context menu hide
253
+ on('context-menu-hide', () => {
254
+ hideContextMenu();
255
+ });
256
+
257
+ // Render frame post — draw minimap
258
+ on('render-frame-post', () => {
259
+ if (isMinimapVisible()) drawMinimap();
260
+ });
261
+
262
+
263
+ // ═══════════════════════════════════════════
264
+ // 6. DETAIL PANEL CALLBACKS
265
+ // ═══════════════════════════════════════════
266
+
267
+ setDetailCallbacks({
268
+ navigateToNode: (node) => {
269
+ const g = getGraph();
270
+ if (!g || !node) return;
271
+ const cards = getAllCards();
272
+ const card = cards.find(c => c.node.id === node.id);
273
+ if (card) g.centerAt(card.x, card.y, 500);
274
+ },
275
+ refreshGraph: () => applyGraphData(),
276
+ scheduleRemoval: () => scheduleGraphRemoval(),
277
+ cancelRemoval: () => cancelScheduledRemoval(),
278
+ });
279
+
280
+
281
+ // ═══════════════════════════════════════════
282
+ // 7. BOOT SEQUENCE
283
+ // ═══════════════════════════════════════════
284
+
285
+ async function boot() {
286
+ try {
287
+ // Restore interface customization + active skin before anything renders
288
+ restoreInterfaceConfig();
289
+ restoreSkin();
290
+
291
+ // Pre-flight health check
292
+ try {
293
+ const healthRes = await fetch('/api/health');
294
+ const health = await healthRes.json();
295
+ if (!health.ok) {
296
+ const messages = {
297
+ db_missing: [t('loading.health.databaseUnreachable.title'), health.detail || t('loading.health.databaseUnreachable.sub')],
298
+ db_error: [t('loading.health.databaseUnreachable.title'), health.detail || t('loading.health.databaseUnreachable.sub')],
299
+ remote_unreachable: [t('loading.health.remoteUnreachable.title'), health.detail || t('loading.health.remoteUnreachable.sub')],
300
+ auth_error: [t('loading.health.authError.title'), health.detail || t('loading.health.authError.sub')],
301
+ };
302
+ const [title, sub] = messages[health.reason] || [t('loading.health.connectionError.title'), health.detail || t('loading.health.connectionError.sub')];
303
+ showLoadingError(title, sub, !!health.canAutoStart);
304
+ return;
305
+ }
306
+ } catch {}
307
+
308
+ // Fetch all memories
309
+ const res = await fetch('/api/memories');
310
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
311
+ const data = await res.json();
312
+
313
+ state.allNodes = normalizeNodes(data.nodes);
314
+ state.allLinks = data.links;
315
+
316
+ // Fetch category definitions
317
+ await loadCategories();
318
+
319
+ // Discover all categories
320
+ const presentCats = new Set(state.allNodes.map(n => n.payload.category));
321
+ state.activeCategories = new Set([...presentCats, ...state.allCategoryNames]);
322
+
323
+ // Build category sidebar
324
+ buildCategorySidebar(presentCats);
325
+
326
+ // Init the 2D canvas renderer (skip if visualization is disabled)
327
+ const container = document.getElementById('graph-container');
328
+ const vizEnabled = loadIfaceConfig().visualizationEnabled !== false;
329
+ let g = null;
330
+
331
+ if (vizEnabled && !getGraph()) {
332
+ g = initGraph(container, {
333
+ onRenderFramePost: () => {
334
+ if (isMinimapVisible()) drawMinimap();
335
+ },
336
+ });
337
+
338
+ // Init overlays
339
+ initMinimap(g);
340
+ initLasso(g);
341
+ initContextMenu(g);
342
+ }
343
+
344
+ // Apply data to compute layout and start rendering
345
+ applyGraphData();
346
+
347
+ // Update stats
348
+ updateStats();
349
+
350
+ // Signal data is ready
351
+ emit('data-loaded', data);
352
+
353
+ // Restore previously open memory cards
354
+ restoreOpenCards();
355
+
356
+ // Handle view-switch handoff
357
+ const switchNodeId = sessionStorage.getItem('neural-selected-node-switch');
358
+ if (switchNodeId) {
359
+ sessionStorage.removeItem('neural-selected-node-switch');
360
+ const node = state.allNodes.find(n => n.id === switchNodeId);
361
+ if (node) {
362
+ state.selectedNodeId = switchNodeId;
363
+ openMemoryCard(node);
364
+ setTimeout(() => {
365
+ if (g) {
366
+ const cards = getAllCards();
367
+ const card = cards.find(c => c.node.id === switchNodeId);
368
+ if (card) g.centerAt(card.x, card.y, 500);
369
+ }
370
+ }, 600);
371
+ }
372
+ }
373
+
374
+ // Fetch trash count
375
+ try { emit('trash:refresh'); } catch {}
376
+
377
+ // Fade out loading
378
+ hideLoading(400);
379
+
380
+ // Mark boot complete
381
+ _bootComplete = true;
382
+
383
+ } catch (err) {
384
+ console.error('Init error:', err);
385
+ const isNetworkError = err.message === 'Failed to fetch' || err.name === 'TypeError';
386
+ showLoadingError(
387
+ isNetworkError ? t('loading.serverOffline') : t('loading.connectionFailed'),
388
+ isNetworkError ? t('loading.serverNotRunning') : err.message,
389
+ false,
390
+ isNetworkError
391
+ );
392
+ }
393
+ }
394
+
395
+
396
+ // ═══════════════════════════════════════════
397
+ // 8. INIT ALL SHARED UI SYSTEMS
398
+ // ═══════════════════════════════════════════
399
+
400
+ initLoading({ onInit: boot });
401
+ initKeybinds();
402
+ initTooltip();
403
+ initPanelSystem();
404
+ initPinToggle();
405
+ initNavbar();
406
+ initMenubar();
407
+ initSearch();
408
+ initSidebar();
409
+ initDetailPanel();
410
+ initSettings();
411
+ initTrash();
412
+ initBookmarks();
413
+ initResume();
414
+ initLayouts();
415
+ initWorkspaces();
416
+ initInvite();
417
+ initSync();
418
+ initHelp();
419
+ initMultiSelect();
420
+ initStats();
421
+ initExplorer();
422
+ initFileExplorer();
423
+ initSkillsStudio();
424
+ initAutomationStudio();
425
+ initImageGallery();
426
+ initCommandRunner();
427
+ initTerminal();
428
+ initLink();
429
+ clearGameOnLoad();
430
+ initWhiteboard();
431
+ initCostWidget();
432
+ initGames();
433
+ initTutorial();
434
+
435
+ // View switch handler
436
+ {
437
+ const switchBtn = document.querySelector('.view-toggle-btn:not(.active)');
438
+ if (switchBtn) {
439
+ switchBtn.addEventListener('click', (e) => {
440
+ e.preventDefault();
441
+ if (state.selectedNodeId) sessionStorage.setItem('neural-selected-node-switch', state.selectedNodeId);
442
+ window.location.href = switchBtn.getAttribute('href');
443
+ });
444
+ }
445
+ }
446
+
447
+ // Window resize handler
448
+ window.addEventListener('resize', () => {
449
+ clampPanelsToViewport();
450
+ });
451
+
452
+ // Visualization toggle — pause/resume 2D rendering
453
+ let _bootComplete = false;
454
+ on('viz:toggle', (enabled) => {
455
+ if (!_bootComplete) return;
456
+ if (enabled) {
457
+ if (!getGraph()) {
458
+ // First-time init if graph was never created (was disabled at boot)
459
+ const container = document.getElementById('graph-container');
460
+ const g = initGraph(container, {
461
+ onRenderFramePost: () => {
462
+ if (isMinimapVisible()) drawMinimap();
463
+ },
464
+ });
465
+ initMinimap(g);
466
+ initLasso(g);
467
+ initContextMenu(g);
468
+ applyGraphData();
469
+ }
470
+ // Show the main canvas (it's position:fixed, not affected by container opacity)
471
+ const mainCanvas = document.getElementById('canvas-main');
472
+ if (mainCanvas) mainCanvas.classList.remove('viz-hidden-2d');
473
+ // Restart the render loop
474
+ startAnimation();
475
+ // Restore minimap to user's preference
476
+ restoreMinimap();
477
+ } else {
478
+ // Stop the render loop entirely — no wasted frames in focus mode
479
+ stopAnimation();
480
+ stopBackground();
481
+ // Hide the main canvas when entering focus mode
482
+ const mainCanvas = document.getElementById('canvas-main');
483
+ if (mainCanvas) mainCanvas.classList.add('viz-hidden-2d');
484
+ // Always hide minimap in focus mode
485
+ forceHideMinimap();
486
+ }
487
+ });
488
+
489
+ // Focus mode isolation — zero-resource mode for 2D
490
+ on('focus:enter', () => {
491
+ state.hoveredNodeId = null;
492
+ clearLasso();
493
+ hideContextMenu();
494
+ pauseInteraction();
495
+ });
496
+
497
+ on('focus:exit', () => {
498
+ resumeInteraction();
499
+ });
500
+
501
+ // Workspace scene snapshot (2D)
502
+ on('workspace:get-scene', (callback) => {
503
+ const graph = getGraph();
504
+ if (!graph) return callback({ nodePositions: {}, camera: null });
505
+ const gd = graph.graphData();
506
+ const positions = {};
507
+ for (const n of gd.nodes) {
508
+ if (n.x != null) positions[n.id] = { x: n.x, y: n.y };
509
+ }
510
+ callback({ nodePositions: positions, camera: null });
511
+ });
512
+
513
+ on('workspace:restore-scene', ({ nodePositions }) => {
514
+ if (nodePositions && Object.keys(nodePositions).length > 0) {
515
+ storage.setItem(KEYS.NODE_POS_2D, JSON.stringify(nodePositions));
516
+ }
517
+ applyGraphData();
518
+ });
519
+
520
+ // Boot
521
+ boot();