@mindexec/cli 0.2.446 → 0.2.448

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 (34) hide show
  1. package/README.md +36 -6
  2. package/electron/main.cjs +347 -0
  3. package/electron/source-smoke.mjs +39 -0
  4. package/electron/windows-package-smoke.mjs +147 -0
  5. package/package.json +74 -14
  6. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  7. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  8. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  9. package/remote-hub.js +1 -1
  10. package/scripts/remote-fleet-render-smoke.mjs +74 -36
  11. package/scripts/remote-hub-smoke.mjs +7 -0
  12. package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1 -3
  13. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +199 -100
  14. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js +902 -0
  15. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +56 -385
  16. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +90 -134
  17. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +167 -24
  18. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +92 -50
  19. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +35 -12
  20. package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +35 -2
  21. package/wwwroot/_framework/{MindExecution.Core.djyzj5mxyk.dll → MindExecution.Core.mswl4wlkm9.dll} +0 -0
  22. package/wwwroot/_framework/{MindExecution.Kernel.6e5cj9aijz.dll → MindExecution.Kernel.zupeldfptg.dll} +0 -0
  23. package/wwwroot/_framework/{MindExecution.Plugins.Admin.siulh9tfrf.dll → MindExecution.Plugins.Admin.hq0vyqnqtn.dll} +0 -0
  24. package/wwwroot/_framework/{MindExecution.Plugins.Business.8cjtrc7qd3.dll → MindExecution.Plugins.Business.pucw3o7rno.dll} +0 -0
  25. package/wwwroot/_framework/{MindExecution.Plugins.Concept.rpp78mc75u.dll → MindExecution.Plugins.Concept.557tzzkrrx.dll} +0 -0
  26. package/wwwroot/_framework/{MindExecution.Plugins.Directory.wfv0ff9v4u.dll → MindExecution.Plugins.Directory.zh1ddg1fn6.dll} +0 -0
  27. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.jdppnbd6g4.dll → MindExecution.Plugins.PlanMaster.0z9pzynpu9.dll} +0 -0
  28. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.a43f2q3pkw.dll → MindExecution.Plugins.YouTube.y8g77r54fa.dll} +0 -0
  29. package/wwwroot/_framework/{MindExecution.Shared.gwtyj0e9lw.dll → MindExecution.Shared.1ymsdbwid2.dll} +0 -0
  30. package/wwwroot/_framework/{MindExecution.Web.j3zaapcxtt.dll → MindExecution.Web.bb1txupuv0.dll} +0 -0
  31. package/wwwroot/_framework/blazor.boot.json +21 -21
  32. package/wwwroot/index.html +2 -1
  33. package/wwwroot/service-worker-assets.js +35 -31
  34. package/wwwroot/service-worker.js +1 -1
@@ -0,0 +1,902 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const BUILD_ID = '20260724-near-css3d-hotpath-v001';
5
+ const projectedCorners = Array.from({ length: 4 }, () => new THREE.Vector3());
6
+
7
+ function createPerfCounters() {
8
+ return {
9
+ buildId: BUILD_ID,
10
+ hitTest: {
11
+ fullBoardFallbackCount: 0,
12
+ candidateSource: '',
13
+ candidateCount: 0,
14
+ elementsFromPointCalls: 0,
15
+ projectedFrameCalculations: 0
16
+ },
17
+ selection: {
18
+ nodesVisited: 0,
19
+ domQueries: 0
20
+ },
21
+ css3d: {
22
+ visibilityPatchEntered: 0,
23
+ visibilityPatchExited: 0,
24
+ visibilityPatchFallbacks: 0,
25
+ sceneObjectsVisited: 0
26
+ }
27
+ };
28
+ }
29
+
30
+ function ensurePerfCounters(module) {
31
+ if (!module) return null;
32
+ if (!module._nearCss3dPerfCounters ||
33
+ module._nearCss3dPerfCounters.buildId !== BUILD_ID) {
34
+ module._nearCss3dPerfCounters = createPerfCounters();
35
+ }
36
+ return module._nearCss3dPerfCounters;
37
+ }
38
+
39
+ function increment(module, section, key, amount = 1) {
40
+ const counters = ensurePerfCounters(module);
41
+ const target = counters?.[section];
42
+ if (!target || !(key in target)) return;
43
+ target[key] = Number(target[key] || 0) + Number(amount || 0);
44
+ }
45
+
46
+ function recordHitCandidates(module, source, count) {
47
+ const hitTest = ensurePerfCounters(module)?.hitTest;
48
+ if (!hitTest) return;
49
+ hitTest.candidateSource = String(source || '');
50
+ hitTest.candidateCount = Math.max(0, Number(count || 0));
51
+ }
52
+
53
+ function getPerfSnapshot(module) {
54
+ const counters = ensurePerfCounters(module);
55
+ if (!counters) return null;
56
+ return {
57
+ buildId: counters.buildId,
58
+ hitTest: { ...counters.hitTest },
59
+ selection: { ...counters.selection },
60
+ css3d: { ...counters.css3d }
61
+ };
62
+ }
63
+
64
+ function resetPerfCounters(module) {
65
+ if (!module) return false;
66
+ module._nearCss3dPerfCounters = createPerfCounters();
67
+ return true;
68
+ }
69
+
70
+ function createPointerHitContext(module, event, viewportMetrics = null) {
71
+ return {
72
+ module,
73
+ event,
74
+ clientX: Number(event?.clientX || 0),
75
+ clientY: Number(event?.clientY || 0),
76
+ viewportMetrics,
77
+ domStack: undefined,
78
+ worldPoint: undefined,
79
+ candidateIds: undefined,
80
+ candidateSource: '',
81
+ cssHit: undefined,
82
+ projectedFrames: new Map()
83
+ };
84
+ }
85
+
86
+ function getDomStack(module, context) {
87
+ if (!context) return [];
88
+ if (context.domStack !== undefined) return context.domStack;
89
+ increment(module, 'hitTest', 'elementsFromPointCalls');
90
+ context.domStack = typeof document !== 'undefined' &&
91
+ typeof document.elementsFromPoint === 'function'
92
+ ? document.elementsFromPoint(context.clientX, context.clientY)
93
+ : [];
94
+ return context.domStack;
95
+ }
96
+
97
+ function getContextWorldPoint(context, factory) {
98
+ if (!context) return typeof factory === 'function' ? factory() : null;
99
+ if (context.worldPoint !== undefined) return context.worldPoint;
100
+ const point = typeof factory === 'function' ? factory() : null;
101
+ context.worldPoint = point
102
+ ? new THREE.Vector3(Number(point.x || 0), Number(point.y || 0), Number(point.z || 0))
103
+ : null;
104
+ return context.worldPoint;
105
+ }
106
+
107
+ function getContextCandidateIds(module, context, factory, source = '') {
108
+ if (!context) {
109
+ const ids = typeof factory === 'function' ? factory() : [];
110
+ recordHitCandidates(module, source, Array.isArray(ids) ? ids.length : 0);
111
+ return ids;
112
+ }
113
+ if (context.candidateIds !== undefined) return context.candidateIds;
114
+ context.candidateIds = typeof factory === 'function' ? factory() : [];
115
+ context.candidateSource = String(source || '');
116
+ recordHitCandidates(
117
+ module,
118
+ context.candidateSource,
119
+ Array.isArray(context.candidateIds) ? context.candidateIds.length : 0
120
+ );
121
+ return context.candidateIds;
122
+ }
123
+
124
+ function getProjectedClientFrame(module, entry, context, viewportMetrics, cacheKey = null) {
125
+ if (!module?.camera || !entry) return null;
126
+ const metrics = context?.viewportMetrics || viewportMetrics || null;
127
+ if (!metrics || !(metrics.width > 0 && metrics.height > 0)) return null;
128
+
129
+ const frameKey = cacheKey || entry;
130
+ const cachedFrame = context?.projectedFrames?.get?.(frameKey);
131
+ if (cachedFrame) return cachedFrame;
132
+
133
+ const sourceObject = entry.glObject || entry.cssObject;
134
+ const position = sourceObject?.position;
135
+ if (!position) return null;
136
+ const width = Number(
137
+ entry.glObject?.userData?.worldWidth ??
138
+ entry.cssObject?.userData?.worldWidth ??
139
+ entry.model?.width ??
140
+ entry.model?.Width ??
141
+ 0
142
+ );
143
+ const height = Number(
144
+ entry.glObject?.userData?.worldHeight ??
145
+ entry.cssObject?.userData?.worldHeight ??
146
+ entry.model?.height ??
147
+ entry.model?.Height ??
148
+ 0
149
+ );
150
+ if (!(width > 0 && height > 0)) return null;
151
+
152
+ const z = Number(position.z || 0);
153
+ projectedCorners[0].set(position.x, position.y, z);
154
+ projectedCorners[1].set(position.x + width, position.y, z);
155
+ projectedCorners[2].set(position.x, position.y - height, z);
156
+ projectedCorners[3].set(position.x + width, position.y - height, z);
157
+
158
+ let left = Infinity;
159
+ let right = -Infinity;
160
+ let top = Infinity;
161
+ let bottom = -Infinity;
162
+ for (let i = 0; i < projectedCorners.length; i++) {
163
+ const corner = projectedCorners[i].project(module.camera);
164
+ const x = Number(metrics.left || 0) + ((corner.x + 1) * metrics.width / 2);
165
+ const y = Number(metrics.top || 0) + ((-corner.y + 1) * metrics.height / 2);
166
+ if (x < left) left = x;
167
+ if (x > right) right = x;
168
+ if (y < top) top = y;
169
+ if (y > bottom) bottom = y;
170
+ }
171
+
172
+ const frame = { left, right, top, bottom };
173
+ context?.projectedFrames?.set?.(frameKey, frame);
174
+ increment(module, 'hitTest', 'projectedFrameCalculations');
175
+ return frame;
176
+ }
177
+
178
+ function getDomRefs(entry, module = null, cssObjectOverride = null) {
179
+ const cssObject = cssObjectOverride || entry?.cssObject || null;
180
+ const wrapper = cssObject?.element || null;
181
+ if (!wrapper) return null;
182
+ const version = Number(entry?._css3dDomVersion || cssObject?.userData?._domVersion || 0);
183
+ const firstChild = wrapper.firstElementChild || null;
184
+ const cached = entry?.domRefs || cssObject?.userData?.domRefs || null;
185
+ if (cached?.wrapper === wrapper &&
186
+ cached.firstChild === firstChild &&
187
+ cached.version === version) {
188
+ return cached;
189
+ }
190
+
191
+ const query = (selector) => {
192
+ increment(module, 'selection', 'domQueries');
193
+ return wrapper.querySelector?.(selector) || null;
194
+ };
195
+ const refs = {
196
+ version,
197
+ wrapper,
198
+ firstChild,
199
+ innerRoot: query('.node-container, .map-node, .css3d-dynamic-node'),
200
+ response: query('.node-response, [id^="node-response-"]'),
201
+ textarea: query('textarea, [contenteditable="true"]'),
202
+ scrollable: query('.csv-table-scroll, .node-response, .note-content, .markdown-body, .code-body, .map-node-memo__body-view'),
203
+ memoTitle: query('.map-node-memo__title'),
204
+ memoBody: query('.map-node-memo__body'),
205
+ memoBodyView: query('.map-node-memo__body-view'),
206
+ resizeHandles: Array.from(wrapper.querySelectorAll?.('.resize-handle, [data-resize-handle]') || [])
207
+ };
208
+ if (entry) entry.domRefs = refs;
209
+ cssObject.userData ||= {};
210
+ cssObject.userData.domRefs = refs;
211
+ return refs;
212
+ }
213
+
214
+ function invalidateDomRefs(entry, cssObjectOverride = null) {
215
+ const cssObject = cssObjectOverride || entry?.cssObject || null;
216
+ const nextVersion = Math.max(
217
+ Number(entry?._css3dDomVersion || 0),
218
+ Number(cssObject?.userData?._domVersion || 0)
219
+ ) + 1;
220
+ if (entry) {
221
+ entry._css3dDomVersion = nextVersion;
222
+ entry.domRefs = null;
223
+ }
224
+ if (cssObject) {
225
+ cssObject.userData ||= {};
226
+ cssObject.userData._domVersion = nextVersion;
227
+ cssObject.userData.domRefs = null;
228
+ }
229
+ return nextVersion;
230
+ }
231
+
232
+ function invalidateDomRefsByCssObject(module, cssObject, nodeId = '') {
233
+ const normalizedId = String(nodeId || cssObject?.userData?.nodeId || '').trim();
234
+ const entry = normalizedId ? module?.nodeObjectsById?.get?.(normalizedId) : null;
235
+ return invalidateDomRefs(entry, cssObject);
236
+ }
237
+
238
+ function installTextSource(helpers = {}) {
239
+ const styleState = new WeakMap();
240
+ const suspendedClass = 'mind-map-text-overlay-source-suspended';
241
+ const suspendedAttr = 'data-text-overlay-source-suspended';
242
+
243
+ function getModule() {
244
+ return helpers.getModule?.() || null;
245
+ }
246
+
247
+ function getTextOverlaySourceTargets(nodeEntry) {
248
+ if (!nodeEntry?.cssObject?.element || !helpers.supportsTextOverlay?.(nodeEntry.model)) return [];
249
+ const module = getModule();
250
+ const refs = getDomRefs(nodeEntry, module);
251
+ if (helpers.getTextOverlayRenderMode?.(nodeEntry) === 'memo') {
252
+ return [refs?.memoTitle, refs?.memoBodyView].filter(element =>
253
+ !!element && (element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
254
+ }
255
+ const root = helpers.getTextOverlayRootElement?.(nodeEntry);
256
+ if (!root?.children?.length) return [];
257
+ return Array.from(root.children).filter(element =>
258
+ !!element &&
259
+ !element.classList?.contains?.('resize-handle') &&
260
+ (element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
261
+ }
262
+
263
+ function ensureTextOverlaySourceStyleState(element) {
264
+ if (!element) return null;
265
+ let state = styleState.get(element) || null;
266
+ if (!state) {
267
+ state = {
268
+ opacity: element.style.opacity,
269
+ pointerEvents: element.style.pointerEvents,
270
+ userSelect: element.style.userSelect,
271
+ webkitUserSelect: element.style.webkitUserSelect,
272
+ caretColor: element.style.caretColor,
273
+ contentVisibility: element.style.contentVisibility,
274
+ containIntrinsicSize: element.style.containIntrinsicSize,
275
+ contain: element.style.contain
276
+ };
277
+ styleState.set(element, state);
278
+ }
279
+ return state;
280
+ }
281
+
282
+ function resetTextOverlaySourcePresentation(element) {
283
+ if (!element) return;
284
+ element.classList?.remove?.(suspendedClass);
285
+ element.removeAttribute?.(suspendedAttr);
286
+ element.style.opacity = '';
287
+ element.style.pointerEvents = '';
288
+ element.style.userSelect = '';
289
+ element.style.webkitUserSelect = '';
290
+ element.style.caretColor = '';
291
+ element.style.contentVisibility = '';
292
+ element.style.containIntrinsicSize = '';
293
+ element.style.contain = '';
294
+ }
295
+
296
+ function suspendTextOverlaySourceTarget(element) {
297
+ if (!element) return;
298
+ ensureTextOverlaySourceStyleState(element);
299
+ element.classList?.add?.(suspendedClass);
300
+ element.setAttribute?.(suspendedAttr, 'true');
301
+ element.style.pointerEvents = 'none';
302
+ element.style.userSelect = 'none';
303
+ element.style.webkitUserSelect = 'none';
304
+ element.style.caretColor = 'transparent';
305
+ element.style.opacity = '0';
306
+ element.style.contain = 'layout style paint';
307
+ element.style.contentVisibility = 'visible';
308
+ element.style.containIntrinsicSize = '';
309
+ }
310
+
311
+ function restoreTextOverlaySourceTarget(element) {
312
+ if (!element) return;
313
+ const state = styleState.get(element) || null;
314
+ if (!state) {
315
+ resetTextOverlaySourcePresentation(element);
316
+ return;
317
+ }
318
+ element.classList?.remove?.(suspendedClass);
319
+ element.removeAttribute?.(suspendedAttr);
320
+ Object.assign(element.style, state);
321
+ styleState.delete(element);
322
+ }
323
+
324
+ function stripTextOverlayPresentationOverrides(root) {
325
+ if (!root) return;
326
+ if (root.hasAttribute?.(suspendedAttr) || root.classList?.contains?.(suspendedClass)) {
327
+ resetTextOverlaySourcePresentation(root);
328
+ }
329
+ root.querySelectorAll?.(`[${suspendedAttr}], .${suspendedClass}`)
330
+ ?.forEach?.(resetTextOverlaySourcePresentation);
331
+ }
332
+
333
+ function getNativeTextSelectionSourceNodeId(module) {
334
+ return String(module?._nativeTextSelectionSourceNodeId || '').trim();
335
+ }
336
+
337
+ function hasNativeTextSelectionSource(module, nodeId = null) {
338
+ const activeId = getNativeTextSelectionSourceNodeId(module);
339
+ if (!activeId) return false;
340
+ return nodeId === null || activeId === String(nodeId || '').trim();
341
+ }
342
+
343
+ function setNativeTextSelectionOwnerClass(module, nodeId = null) {
344
+ if (!module) return false;
345
+ const nextId = String(nodeId || '').trim();
346
+ const previousId = String(module._nativeTextSelectionOwnerNodeId || '').trim();
347
+ if (previousId === nextId) return true;
348
+
349
+ const getWrapper = (id) => {
350
+ const entry = id ? module.nodeObjectsById?.get?.(id) : null;
351
+ return getDomRefs(entry, module)?.wrapper || null;
352
+ };
353
+ const previousWrapper = getWrapper(previousId);
354
+ const nextWrapper = getWrapper(nextId);
355
+ if (previousWrapper) {
356
+ previousWrapper.classList?.remove?.('is-text-selection-owner');
357
+ increment(module, 'selection', 'nodesVisited');
358
+ }
359
+ if (nextWrapper) {
360
+ nextWrapper.classList?.add?.('is-text-selection-owner');
361
+ increment(module, 'selection', 'nodesVisited');
362
+ }
363
+ module._nativeTextSelectionOwnerNodeId = nextId || null;
364
+ return true;
365
+ }
366
+
367
+ function activateNativeTextSelectionSource(module, nodeId) {
368
+ const id = String(nodeId || '').trim();
369
+ if (!module || !id) return false;
370
+ module._nativeTextSelectionSourceNodeId = id;
371
+ setNativeTextSelectionOwnerClass(module, id);
372
+ helpers.ensureTextOverlaySourceVisible?.(module, id);
373
+ return true;
374
+ }
375
+
376
+ function clearNativeTextSelectionSource(module, nodeId = null) {
377
+ const activeId = getNativeTextSelectionSourceNodeId(module);
378
+ const requestedId = nodeId === null ? activeId : String(nodeId || '').trim();
379
+ if (!module || !activeId || !requestedId || activeId !== requestedId) return false;
380
+ module._nativeTextSelectionSourceNodeId = null;
381
+ setNativeTextSelectionOwnerClass(module, null);
382
+ return true;
383
+ }
384
+
385
+ function isTextOverlaySelectionNode(module, nodeEntry) {
386
+ const contentType = String(nodeEntry?.model?.contentType ?? nodeEntry?.model?.ContentType ?? '').toLowerCase();
387
+ if (contentType !== 'text' && contentType !== 'markdown') return false;
388
+ const nodeId = String(helpers.getNodeId?.(nodeEntry?.model) || '').trim();
389
+ return hasNativeTextSelectionSource(module, nodeId);
390
+ }
391
+
392
+ function setTextOverlaySourceActive(nodeEntry, isActive) {
393
+ if (helpers.isCss3dMediaNode?.(nodeEntry?.model)) {
394
+ helpers.restoreCss3dMediaOverlayState?.(nodeEntry.model, nodeEntry.cssObject);
395
+ nodeEntry._textOverlayActive = false;
396
+ nodeEntry._css3dSourceSuspended = false;
397
+ return;
398
+ }
399
+ const host = helpers.getTextOverlayHostElement?.(nodeEntry);
400
+ if (!host?.classList) return;
401
+ host.classList.toggle('mind-map-text-overlay-active', !!isActive);
402
+ getTextOverlaySourceTargets(nodeEntry).forEach(target => {
403
+ if (isActive) suspendTextOverlaySourceTarget(target);
404
+ else restoreTextOverlaySourceTarget(target);
405
+ });
406
+ nodeEntry._textOverlayActive = nodeEntry._css3dSourceSuspended = !!isActive;
407
+ }
408
+
409
+ return {
410
+ getTextOverlaySourceTargets,
411
+ ensureTextOverlaySourceStyleState,
412
+ resetTextOverlaySourcePresentation,
413
+ suspendTextOverlaySourceTarget,
414
+ restoreTextOverlaySourceTarget,
415
+ stripTextOverlayPresentationOverrides,
416
+ getNativeTextSelectionSourceNodeId,
417
+ hasNativeTextSelectionSource,
418
+ setNativeTextSelectionOwnerClass,
419
+ activateNativeTextSelectionSource,
420
+ clearNativeTextSelectionSource,
421
+ isTextOverlaySelectionNode,
422
+ setTextOverlaySourceActive
423
+ };
424
+ }
425
+
426
+ function installOverlayGeometry(helpers = {}) {
427
+ function getTextOverlayPlacementInfo(module, element) {
428
+ if (!module?.container || !element) return null;
429
+ const rect = element.getBoundingClientRect();
430
+ const containerRect = module.container.getBoundingClientRect();
431
+ const width = Math.max(0, rect.width || 0);
432
+ const height = Math.max(0, rect.height || 0);
433
+ if (width < 1 || height < 1) return null;
434
+ const left = rect.left - containerRect.left;
435
+ const top = rect.top - containerRect.top;
436
+ return {
437
+ left,
438
+ top,
439
+ width,
440
+ height,
441
+ baseWidth: Math.max(1, Number(element.offsetWidth || width || 1)),
442
+ baseHeight: Math.max(1, Number(element.offsetHeight || height || 1)),
443
+ right: left + width,
444
+ bottom: top + height
445
+ };
446
+ }
447
+
448
+ function doesTextOverlayRectOverlap(a, b, padding = 0) {
449
+ if (!a || !b) return false;
450
+ const inset = Number.isFinite(Number(padding)) ? Number(padding) : 0;
451
+ return !(
452
+ (a.left + a.width + inset) < b.left ||
453
+ (b.left + b.width + inset) < a.left ||
454
+ (a.top + a.height + inset) < b.top ||
455
+ (b.top + b.height + inset) < a.top
456
+ );
457
+ }
458
+
459
+ function isTextOverlayPlacementVisible(module, placement, options = {}) {
460
+ if (!module?.container || !placement) return false;
461
+ const { ignoreMinSize = false } = options;
462
+ if (!ignoreMinSize &&
463
+ (placement.width < Number(helpers.minWidth || 0) ||
464
+ placement.height < Number(helpers.minHeight || 0))) {
465
+ return false;
466
+ }
467
+ const maxWidth = Number(module.container.clientWidth || 0);
468
+ const maxHeight = Number(module.container.clientHeight || 0);
469
+ if (!(maxWidth > 0) || !(maxHeight > 0)) return false;
470
+ return !(
471
+ placement.right < 0 ||
472
+ placement.left > maxWidth ||
473
+ placement.bottom < 0 ||
474
+ placement.top > maxHeight
475
+ );
476
+ }
477
+
478
+ function getTextOverlayPriority(module, nodeEntry) {
479
+ const nodeModel = nodeEntry?.model;
480
+ const nodeId = String(helpers.getNodeId?.(nodeModel) || '').trim();
481
+ if (!nodeModel || !nodeId) return Number.NEGATIVE_INFINITY;
482
+ let priority = 0;
483
+ if (String(module?.selectedNodeIdJs || '').trim() === nodeId) priority += 100000;
484
+ else if (module?.multiSelectedNodeIds?.has?.(nodeId)) priority += 50000;
485
+ const width = Math.max(1, Number(nodeModel.width || nodeModel.Width || 0));
486
+ const height = Math.max(1, Number(nodeModel.height || nodeModel.Height || 0));
487
+ priority += Math.min(6000, (width * height) / 18);
488
+ if (module?.camera) {
489
+ const centerX = Number(nodeModel.positionX ?? nodeModel.PositionX ?? nodeModel.x ?? nodeModel.X ?? 0) + (width * 0.5);
490
+ const centerY = Number(nodeModel.positionY ?? nodeModel.PositionY ?? nodeModel.y ?? nodeModel.Y ?? 0) - (height * 0.5);
491
+ priority += Math.max(
492
+ 0,
493
+ 24000 -
494
+ Math.abs(centerX - Number(module.camera.position?.x || 0)) -
495
+ Math.abs(centerY - Number(module.camera.position?.y || 0))
496
+ );
497
+ }
498
+ const zIndex = Number(nodeEntry?.cssObject?.element?.style?.zIndex || 0);
499
+ if (Number.isFinite(zIndex)) priority += zIndex * 10;
500
+ return priority;
501
+ }
502
+
503
+ function isAlwaysTextOverlayNode(nodeEntry) {
504
+ const contentType = String(
505
+ nodeEntry?.model?.contentType ??
506
+ nodeEntry?.model?.ContentType ??
507
+ ''
508
+ ).toLowerCase();
509
+ return contentType === 'markdown' || contentType === 'text';
510
+ }
511
+
512
+ function getTextOverlayContentSignature(nodeEntry) {
513
+ const model = nodeEntry?.model || {};
514
+ const contentType = String(model.contentType ?? model.ContentType ?? '').toLowerCase();
515
+ const prompt = String(model.prompt ?? model.Prompt ?? '');
516
+ const response = String(model.response ?? model.Response ?? '');
517
+ const isLoading = (model.isLoading ?? model.IsLoading ?? false) ? '1' : '0';
518
+ const width = Math.max(0, Number(model.width ?? model.Width ?? 0));
519
+ const height = Math.max(0, Number(model.height ?? model.Height ?? 0));
520
+ return `${contentType}||${prompt}||${response}||${isLoading}||${width}||${height}`;
521
+ }
522
+
523
+ function getTextOverlayLayoutSignature(sourceElement, mode = 'full', hostPlacement = null) {
524
+ if (!sourceElement) return '';
525
+ if (mode === 'memo') {
526
+ const titleInput = sourceElement.querySelector('.map-node-memo__title');
527
+ const bodyView = sourceElement.querySelector('.map-node-memo__body-view');
528
+ const hostWidth = Math.round(Number(hostPlacement?.baseWidth || sourceElement.offsetWidth || 0));
529
+ const hostHeight = Math.round(Number(hostPlacement?.baseHeight || sourceElement.offsetHeight || 0));
530
+ const titleSignature = titleInput
531
+ ? `${titleInput.offsetLeft}:${titleInput.offsetTop}:${titleInput.offsetWidth}:${titleInput.offsetHeight}:${titleInput.style.display}`
532
+ : 'title:none';
533
+ const bodySignature = bodyView
534
+ ? `${bodyView.offsetLeft}:${bodyView.offsetTop}:${bodyView.offsetWidth}:${bodyView.offsetHeight}:${bodyView.style.display}`
535
+ : 'body:none';
536
+ return `${mode}||${hostWidth}x${hostHeight}||${titleSignature}||${bodySignature}`;
537
+ }
538
+ const rootWidth = Math.round(Number(sourceElement.offsetWidth || 0));
539
+ const rootHeight = Math.round(Number(sourceElement.offsetHeight || 0));
540
+ const childSignature = Array.from(sourceElement.children || [])
541
+ .map(child => `${child.tagName}:${child.offsetWidth}:${child.offsetHeight}:${child.style.display}`)
542
+ .join('|');
543
+ return `${mode}||${rootWidth}x${rootHeight}||${childSignature}`;
544
+ }
545
+
546
+ return {
547
+ getTextOverlayPlacementInfo,
548
+ doesTextOverlayRectOverlap,
549
+ isTextOverlayPlacementVisible,
550
+ getTextOverlayPriority,
551
+ isAlwaysTextOverlayNode,
552
+ getTextOverlayContentSignature,
553
+ getTextOverlayLayoutSignature
554
+ };
555
+ }
556
+
557
+ function getNodeBounds(entry) {
558
+ const shared = window.MindMapNodeBounds?.getNodeWorldBounds?.(entry);
559
+ if (shared) return shared;
560
+ const model = entry?.model || null;
561
+ const object = entry?.glObject || entry?.cssObject || null;
562
+ if (!model && !object) return null;
563
+ const width = Math.max(1, Number(
564
+ entry?.glObject?.userData?.worldWidth ??
565
+ entry?.cssObject?.userData?.worldWidth ??
566
+ model?.width ??
567
+ model?.Width ??
568
+ 400
569
+ ));
570
+ const height = Math.max(1, Number(
571
+ entry?.glObject?.userData?.worldHeight ??
572
+ entry?.cssObject?.userData?.worldHeight ??
573
+ model?.height ??
574
+ model?.Height ??
575
+ 200
576
+ ));
577
+ const x = Number(object?.position?.x ?? model?.positionX ?? model?.x ?? 0);
578
+ const y = Number(object?.position?.y ?? model?.positionY ?? model?.y ?? 0);
579
+ return { minX: x, maxX: x + width, minY: y - height, maxY: y };
580
+ }
581
+
582
+ function getSpatialGridKeysForBounds(module, entry) {
583
+ const bounds = getNodeBounds(entry);
584
+ if (!bounds) return new Set();
585
+ const cellSize = Math.max(1, Number(module?.GRID_CELL_SIZE || 500));
586
+ const keys = new Set();
587
+ const startX = Math.floor(bounds.minX / cellSize);
588
+ const endX = Math.floor(bounds.maxX / cellSize);
589
+ const startY = Math.floor(bounds.minY / cellSize);
590
+ const endY = Math.floor(bounds.maxY / cellSize);
591
+ for (let x = startX; x <= endX; x++) {
592
+ for (let y = startY; y <= endY; y++) keys.add(`${x}:${y}`);
593
+ }
594
+ return keys;
595
+ }
596
+
597
+ function setEntrySpatialKeys(entry, keys) {
598
+ if (!entry) return;
599
+ entry._spatialGridKeys = keys;
600
+ if (entry.glObject) {
601
+ entry.glObject.userData ||= {};
602
+ entry.glObject.userData.spatialGridKeys = keys;
603
+ }
604
+ if (entry.cssObject) {
605
+ entry.cssObject.userData ||= {};
606
+ entry.cssObject.userData.spatialGridKeys = keys;
607
+ }
608
+ }
609
+
610
+ function collectSpatialRectCandidateIds(module, rect) {
611
+ if (!module?.spatialGrid || module._spatialIndexRepairState || !rect) return null;
612
+ const cellSize = Math.max(1, Number(module.GRID_CELL_SIZE || 500));
613
+ const ids = [];
614
+ const seen = new Set();
615
+ const startX = Math.floor(Number(rect.left || 0) / cellSize);
616
+ const endX = Math.floor(Number(rect.right || 0) / cellSize);
617
+ const startY = Math.floor(Number(rect.bottom || 0) / cellSize);
618
+ const endY = Math.floor(Number(rect.top || 0) / cellSize);
619
+ for (let x = startX; x <= endX; x++) {
620
+ for (let y = startY; y <= endY; y++) {
621
+ module.spatialGrid.get(`${x}:${y}`)?.forEach?.(nodeId => {
622
+ const id = String(nodeId || '').trim();
623
+ if (id && !seen.has(id)) {
624
+ seen.add(id);
625
+ ids.push(id);
626
+ }
627
+ });
628
+ }
629
+ }
630
+ return ids;
631
+ }
632
+
633
+ function getBoundedFallbackIds(module) {
634
+ const ids = new Set();
635
+ const add = (value) => {
636
+ const id = String(value || '').trim();
637
+ if (id && module?.nodeObjectsById?.has?.(id)) ids.add(id);
638
+ };
639
+ module?._visibleIds?.forEach?.(add);
640
+ module?._prevVisibleIds?.forEach?.(add);
641
+ add(module?.selectedNodeIdJs);
642
+ module?.multiSelectedNodeIds?.forEach?.(add);
643
+ add(module?.draggedNodeId);
644
+ add(module?._nativeTextSelectionSourceNodeId);
645
+ add(module?._editingOverlayState?.nodeId);
646
+ add(module?._textOverlayV2State?.editing?.nodeId);
647
+ module?.lodRenderer?._nearCssVisibleIds?.forEach?.(add);
648
+ module?.lodRenderer?._lodImageCssFallbackNodeIds?.forEach?.(add);
649
+ module?.lodRenderer?._lodTemplateCssNodeIds?.forEach?.(add);
650
+ return Array.from(ids);
651
+ }
652
+
653
+ function scheduleSpatialIndexRepair(module, reason = 'index-unavailable') {
654
+ if (!module?.nodeObjectsById || module._spatialIndexRepairState) return false;
655
+ const ownerMap = module.nodeObjectsById;
656
+ const state = {
657
+ ownerMap,
658
+ iterator: ownerMap.entries(),
659
+ reason: String(reason || 'index-unavailable'),
660
+ processed: 0
661
+ };
662
+ module._spatialIndexRepairState = state;
663
+ module.spatialGrid = new Map();
664
+ window.MindCanvasTrace?.emit?.('hitTest.spatialRepairScheduled', {
665
+ reason: state.reason,
666
+ nodeCount: ownerMap.size
667
+ });
668
+
669
+ const schedule = (callback) => {
670
+ if (typeof requestIdleCallback === 'function') requestIdleCallback(callback, { timeout: 120 });
671
+ else setTimeout(() => callback(null), 0);
672
+ };
673
+ const run = (deadline) => {
674
+ if (module._spatialIndexRepairState !== state || module.nodeObjectsById !== ownerMap) return;
675
+ let processedThisSlice = 0;
676
+ while (processedThisSlice < 128 &&
677
+ (!deadline?.timeRemaining || deadline.timeRemaining() > 1)) {
678
+ const next = state.iterator.next();
679
+ if (next.done) {
680
+ module._spatialIndexRepairState = null;
681
+ module.logicWorkerBridge?.rebuildNodeTables?.(module, {
682
+ reason: 'hit-test-spatial-repair'
683
+ });
684
+ window.MindCanvasTrace?.emit?.('hitTest.spatialRepairCompleted', {
685
+ reason: state.reason,
686
+ processed: state.processed
687
+ });
688
+ return;
689
+ }
690
+ const [nodeId, entry] = next.value;
691
+ const keys = getSpatialGridKeysForBounds(module, entry);
692
+ keys.forEach(key => {
693
+ if (!module.spatialGrid.has(key)) module.spatialGrid.set(key, new Set());
694
+ module.spatialGrid.get(key).add(nodeId);
695
+ });
696
+ setEntrySpatialKeys(entry, keys);
697
+ processedThisSlice++;
698
+ state.processed++;
699
+ }
700
+ schedule(run);
701
+ };
702
+ schedule(run);
703
+ return true;
704
+ }
705
+
706
+ function noteUnavailableIndex(module, reason = 'index-unavailable') {
707
+ window.MindCanvasTrace?.emit?.('hitTest.fullBoardFallback', {
708
+ blocked: true,
709
+ reason
710
+ });
711
+ scheduleSpatialIndexRepair(module, reason);
712
+ }
713
+
714
+ function ensureCssRendererHooks(module) {
715
+ const renderer = module?.cssRenderer || null;
716
+ if (!renderer) return false;
717
+ if (renderer._nearCss3dHooksInstalled === BUILD_ID) return true;
718
+
719
+ const counters = {
720
+ sceneObjectsVisited: 0,
721
+ visibilityPatchEntered: 0,
722
+ visibilityPatchExited: 0
723
+ };
724
+ const existingGetDebugCounters =
725
+ typeof renderer.getDebugCounters === 'function'
726
+ ? renderer.getDebugCounters.bind(renderer)
727
+ : null;
728
+ const existingResetDebugCounters =
729
+ typeof renderer.resetDebugCounters === 'function'
730
+ ? renderer.resetDebugCounters.bind(renderer)
731
+ : null;
732
+ const originalRender =
733
+ typeof renderer.render === 'function'
734
+ ? renderer.render.bind(renderer)
735
+ : null;
736
+
737
+ if (!existingGetDebugCounters && originalRender) {
738
+ renderer.render = (scene, camera) => {
739
+ let visited = 0;
740
+ if (module.renderDebugFlags?.enableFramePerfProbe === true) {
741
+ scene?.traverse?.(() => {
742
+ visited++;
743
+ });
744
+ }
745
+ const result = originalRender(scene, camera);
746
+ counters.sceneObjectsVisited += visited;
747
+ return result;
748
+ };
749
+ }
750
+
751
+ if (typeof renderer.applyVisibilityDiff !== 'function') {
752
+ renderer.applyVisibilityDiff = (enteredObjects, exitedObjects) => {
753
+ const entered = Array.isArray(enteredObjects) ? enteredObjects : [];
754
+ const exited = Array.isArray(exitedObjects) ? exitedObjects : [];
755
+ const cameraElement = renderer.getCameraElement?.() || null;
756
+ let visited = 0;
757
+ const patchObject = (object) => {
758
+ if (!object?.isCSS3DObject || !object.element) return;
759
+ object.updateMatrixWorld?.(true);
760
+ const layoutPrepared =
761
+ object.userData?._residentTransitionPrepared === true ||
762
+ object.userData?._fullResFringePrepared === true;
763
+ object.element.style.removeProperty?.('display');
764
+ if (object.visible !== true && layoutPrepared !== true) {
765
+ object.element.style.display = 'none';
766
+ }
767
+ if (cameraElement && object.element.parentNode !== cameraElement) {
768
+ cameraElement.appendChild(object.element);
769
+ }
770
+ visited++;
771
+ };
772
+ try {
773
+ exited.forEach(patchObject);
774
+ entered.forEach(patchObject);
775
+ } catch (error) {
776
+ return {
777
+ complete: false,
778
+ reason: 'visibility-diff-exception',
779
+ visited,
780
+ error
781
+ };
782
+ }
783
+ counters.visibilityPatchEntered += entered.length;
784
+ counters.visibilityPatchExited += exited.length;
785
+ return {
786
+ complete: true,
787
+ entered: entered.length,
788
+ exited: exited.length,
789
+ visited
790
+ };
791
+ };
792
+ }
793
+
794
+ if (!existingGetDebugCounters) {
795
+ renderer.getDebugCounters = () => ({ ...counters });
796
+ }
797
+ if (!existingResetDebugCounters) {
798
+ renderer.resetDebugCounters = () => {
799
+ counters.sceneObjectsVisited = 0;
800
+ counters.visibilityPatchEntered = 0;
801
+ counters.visibilityPatchExited = 0;
802
+ };
803
+ }
804
+ renderer._nearCss3dHooksInstalled = BUILD_ID;
805
+ return true;
806
+ }
807
+
808
+ function applyVisibilityDiff(module, enteredIds, exitedIds) {
809
+ const fallback = (reason) => {
810
+ increment(module, 'css3d', 'visibilityPatchFallbacks');
811
+ return { complete: false, reason };
812
+ };
813
+ const renderer = module?.cssRenderer;
814
+ ensureCssRendererHooks(module);
815
+ if (!renderer || typeof renderer.applyVisibilityDiff !== 'function') return fallback('renderer-api-unavailable');
816
+ if (module._cssParentRepairNeeded === true) return fallback('parent-repair-pending');
817
+ if ((module._cssTransformDirtyIds?.size || 0) > 0) return fallback('transform-dirty');
818
+
819
+ const cssScene = module.cssScene || module.scene || null;
820
+ const enteredObjects = [];
821
+ const exitedObjects = [];
822
+
823
+ for (const value of enteredIds || []) {
824
+ const nodeId = String(value || '').trim();
825
+ const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
826
+ if (!entry) continue;
827
+ if (entry.currentType !== 'CSS') {
828
+ if (entry.cssObject?.visible === true) return fallback('entered-owner-mismatch');
829
+ continue;
830
+ }
831
+ if (!entry.cssObject?.element || entry.cssObject.visible !== true || entry.isCssDirty === true) {
832
+ return fallback('entered-owner-not-ready');
833
+ }
834
+ if (cssScene && entry.cssObject.parent !== cssScene) return fallback('entered-parent-mismatch');
835
+ enteredObjects.push(entry.cssObject);
836
+ }
837
+
838
+ for (const value of exitedIds || []) {
839
+ const nodeId = String(value || '').trim();
840
+ const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
841
+ const cssObject = entry?.cssObject || null;
842
+ if (!cssObject) continue;
843
+ if (entry.isCssDirty === true) return fallback('exited-content-dirty');
844
+ if (cssObject.parent === cssScene) {
845
+ exitedObjects.push(cssObject);
846
+ } else if (cssObject.visible === true || entry.currentType === 'CSS') {
847
+ return fallback('exited-owner-mismatch');
848
+ }
849
+ }
850
+
851
+ const result = renderer.applyVisibilityDiff(enteredObjects, exitedObjects);
852
+ if (result?.complete !== true) return fallback(result?.reason || 'renderer-patch-failed');
853
+
854
+ increment(module, 'css3d', 'visibilityPatchEntered', Number(result.entered || 0));
855
+ increment(module, 'css3d', 'visibilityPatchExited', Number(result.exited || 0));
856
+ increment(module, 'css3d', 'sceneObjectsVisited', Number(result.visited || 0));
857
+ return {
858
+ complete: true,
859
+ entered: Number(result.entered || 0),
860
+ exited: Number(result.exited || 0),
861
+ visited: Number(result.visited || 0)
862
+ };
863
+ }
864
+
865
+ function replaceGeometryIfSizeChanged(object, key, createGeometry) {
866
+ if (!object || typeof createGeometry !== 'function') return false;
867
+ object.userData ||= {};
868
+ if (object.geometry && object.userData.geometrySizeKey === key) return false;
869
+ const previous = object.geometry || null;
870
+ object.geometry = createGeometry();
871
+ object.userData.geometrySizeKey = key;
872
+ previous?.dispose?.();
873
+ return true;
874
+ }
875
+
876
+ window.MindMapCss3dHotPath = {
877
+ BUILD_ID,
878
+ applyVisibilityDiff,
879
+ collectSpatialRectCandidateIds,
880
+ createPointerHitContext,
881
+ ensureCssRendererHooks,
882
+ ensurePerfCounters,
883
+ getBoundedFallbackIds,
884
+ getContextCandidateIds,
885
+ getContextWorldPoint,
886
+ getDomRefs,
887
+ getDomStack,
888
+ getPerfSnapshot,
889
+ getProjectedClientFrame,
890
+ getSpatialGridKeysForBounds,
891
+ increment,
892
+ installOverlayGeometry,
893
+ installTextSource,
894
+ invalidateDomRefs,
895
+ invalidateDomRefsByCssObject,
896
+ noteUnavailableIndex,
897
+ recordHitCandidates,
898
+ replaceGeometryIfSizeChanged,
899
+ resetPerfCounters,
900
+ scheduleSpatialIndexRepair
901
+ };
902
+ })();