@mindexec/cli 0.2.483 → 0.2.494

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 (70) hide show
  1. package/codex-runtime.js +6 -2
  2. package/electron/main.cjs +56 -32
  3. package/electron/preload.cjs +178 -0
  4. package/electron/source-smoke.mjs +14 -1
  5. package/electron/windows-package-smoke.mjs +16 -0
  6. package/package.json +11 -10
  7. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  8. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  9. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  10. package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -1
  11. package/wwwroot/_content/MindExecution.Shared/js/canvas-chat-task-switch.js +122 -0
  12. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +161 -16
  13. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +68 -2
  14. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +44 -8
  15. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +823 -111
  16. package/wwwroot/_content/MindExecution.Shared/js/mind-map-native-core-bridge.js +399 -0
  17. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +53 -10
  18. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +71 -11
  19. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.js +18 -0
  20. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.wasm +0 -0
  21. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.js +18 -0
  22. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.wasm +0 -0
  23. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-adapter.js +566 -0
  24. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-worker.js +89 -0
  25. package/wwwroot/_content/MindExecution.Shared/native-core/native-core-manifest.json +59 -0
  26. package/wwwroot/_framework/BenchmarkUtils.ytz7pn9azy.dll +0 -0
  27. package/wwwroot/_framework/Edgar.9yqq548b45.dll +0 -0
  28. package/wwwroot/_framework/GraphPlanarityTesting.lgk3vd0bh9.dll +0 -0
  29. package/wwwroot/_framework/Microsoft.Win32.SystemEvents.f8qhom7uq5.dll +0 -0
  30. package/wwwroot/_framework/{MindExecution.Core.zs4n1f9hjc.dll → MindExecution.Core.tre9kny2uo.dll} +0 -0
  31. package/wwwroot/_framework/{MindExecution.Kernel.l9idvg7mp7.dll → MindExecution.Kernel.lvfnhwdksf.dll} +0 -0
  32. package/wwwroot/_framework/{MindExecution.Plugins.Admin.l37qx5d8zi.dll → MindExecution.Plugins.Admin.k2vbe4lt64.dll} +0 -0
  33. package/wwwroot/_framework/{MindExecution.Plugins.Business.d7b282yazn.dll → MindExecution.Plugins.Business.u7i3r45xp5.dll} +0 -0
  34. package/wwwroot/_framework/{MindExecution.Plugins.Concept.iw98n0qz5k.dll → MindExecution.Plugins.Concept.7eoasvev17.dll} +0 -0
  35. package/wwwroot/_framework/{MindExecution.Plugins.Directory.cqgn6pa8di.dll → MindExecution.Plugins.Directory.rhh13u0z6c.dll} +0 -0
  36. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll → MindExecution.Plugins.PlanMaster.xzl2x2cqk4.dll} +0 -0
  37. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.zvpzk7om4z.dll → MindExecution.Plugins.YouTube.945tf0zc9m.dll} +0 -0
  38. package/wwwroot/_framework/{MindExecution.Shared.ovot7q606x.dll → MindExecution.Shared.e0w408b0ti.dll} +0 -0
  39. package/wwwroot/_framework/{MindExecution.Web.bzuaz35jv0.dll → MindExecution.Web.vc6ux7xjcw.dll} +0 -0
  40. package/wwwroot/_framework/RangeTree.iw8h1x5u2y.dll +0 -0
  41. package/wwwroot/_framework/System.Collections.Concurrent.jzwteolu29.dll +0 -0
  42. package/wwwroot/_framework/System.Collections.NonGeneric.uqtvwssxuq.dll +0 -0
  43. package/wwwroot/_framework/System.Collections.Specialized.85qtrfslgb.dll +0 -0
  44. package/wwwroot/_framework/System.Collections.xmhu72xgrp.dll +0 -0
  45. package/wwwroot/_framework/System.ComponentModel.Primitives.excbd02v5j.dll +0 -0
  46. package/wwwroot/_framework/System.ComponentModel.TypeConverter.ek2jcwibb9.dll +0 -0
  47. package/wwwroot/_framework/System.ComponentModel.wfe9zz2icv.dll +0 -0
  48. package/wwwroot/_framework/System.Console.5j283so6ps.dll +0 -0
  49. package/wwwroot/_framework/System.Drawing.Common.xzizafq144.dll +0 -0
  50. package/wwwroot/_framework/System.Private.CoreLib.7ouudb2fbl.dll +0 -0
  51. package/wwwroot/_framework/{System.Text.RegularExpressions.cvkox11l6l.dll → System.Text.RegularExpressions.b0vqxbob08.dll} +0 -0
  52. package/wwwroot/_framework/System.Threading.Tasks.Parallel.9tqazg1b0u.dll +0 -0
  53. package/wwwroot/_framework/System.Threading.Tasks.zl4yo3otxa.dll +0 -0
  54. package/wwwroot/_framework/YamlDotNet.dtey92juka.dll +0 -0
  55. package/wwwroot/_framework/blazor.boot.json +63 -45
  56. package/wwwroot/_framework/{dotnet.native.60hhmnxyoo.wasm → dotnet.native.58bvs6q392.wasm} +0 -0
  57. package/wwwroot/_framework/netstandard.he3m3p1s9q.dll +0 -0
  58. package/wwwroot/index.html +2 -1
  59. package/wwwroot/service-worker-assets.js +128 -56
  60. package/wwwroot/service-worker.js +1 -1
  61. package/wwwroot/_framework/System.Collections.3iuoxbe8my.dll +0 -0
  62. package/wwwroot/_framework/System.Collections.Concurrent.vow3rm1dku.dll +0 -0
  63. package/wwwroot/_framework/System.Collections.NonGeneric.npjkaz40oc.dll +0 -0
  64. package/wwwroot/_framework/System.Collections.Specialized.ugkjbs6p02.dll +0 -0
  65. package/wwwroot/_framework/System.ComponentModel.Primitives.end4v0xe2c.dll +0 -0
  66. package/wwwroot/_framework/System.ComponentModel.TypeConverter.tgtp5sm4iv.dll +0 -0
  67. package/wwwroot/_framework/System.ComponentModel.wupoltkk1t.dll +0 -0
  68. package/wwwroot/_framework/System.Console.9dik0wogo2.dll +0 -0
  69. package/wwwroot/_framework/System.Private.CoreLib.7s8wte759y.dll +0 -0
  70. package/wwwroot/_framework/netstandard.b50t77veor.dll +0 -0
@@ -0,0 +1,122 @@
1
+ let dotnetRef = null;
2
+ let mode = 'chat';
3
+ let attached = false;
4
+ let lastSignature = '';
5
+ let lastObservedAt = 0;
6
+ let selectionTimer = 0;
7
+ let lastSelectionSignature = '';
8
+
9
+ function textarea() {
10
+ return document.getElementById('global-input-textarea');
11
+ }
12
+
13
+ function isCanvasTextInputVisible() {
14
+ const input = textarea();
15
+ if (!input) return false;
16
+ const style = window.getComputedStyle(input);
17
+ return style.display !== 'none' && style.visibility !== 'hidden';
18
+ }
19
+
20
+ function isSendButton(target) {
21
+ const button = target?.closest?.('button');
22
+ if (!button) return false;
23
+ if (!button.closest('.global-ai-input-shell')) return false;
24
+ return !!button.querySelector('.fa-arrow-up');
25
+ }
26
+
27
+ function observe(prompt, event, source) {
28
+ const text = (prompt || '').trim();
29
+ if (!text || !dotnetRef) return;
30
+
31
+ const now = Date.now();
32
+ const signature = `${mode}|${source}|${text}`;
33
+ if (signature === lastSignature && now - lastObservedAt < 450) {
34
+ return;
35
+ }
36
+ lastSignature = signature;
37
+ lastObservedAt = now;
38
+
39
+ if (mode === 'task') {
40
+ event.preventDefault();
41
+ event.stopPropagation();
42
+ event.stopImmediatePropagation?.();
43
+
44
+ const input = textarea();
45
+ if (input) {
46
+ input.value = '';
47
+ input.dispatchEvent(new Event('input', { bubbles: true }));
48
+ }
49
+ }
50
+
51
+ const selectedNodeIds = readSelectedNodeIds();
52
+ void dotnetRef.invokeMethodAsync('OnGlobalCanvasAiSubmitObserved', text, mode, now, selectedNodeIds)
53
+ .catch(error => console.warn('[CanvasChatTaskSwitch] submit callback failed', error));
54
+ }
55
+
56
+ function onKeyDown(event) {
57
+ if (event.key !== 'Enter' || event.shiftKey || event.isComposing) return;
58
+ if (event.target !== textarea() || !isCanvasTextInputVisible()) return;
59
+ observe(event.target.value, event, 'enter');
60
+ }
61
+
62
+ function onClick(event) {
63
+ if (!isSendButton(event.target) || !isCanvasTextInputVisible()) return;
64
+ const input = textarea();
65
+ observe(input?.value, event, 'button');
66
+ }
67
+
68
+ function readSelectedNodeIds() {
69
+ try {
70
+ const ids = globalThis.mindMap?.getSelectedNodeIds?.();
71
+ if (!Array.isArray(ids)) return [];
72
+ return ids.filter(Boolean).map(value => String(value));
73
+ } catch {
74
+ return [];
75
+ }
76
+ }
77
+
78
+ function pushSelection(force = false) {
79
+ if (!dotnetRef) return;
80
+ const ids = readSelectedNodeIds();
81
+ const signature = ids.join('|');
82
+ if (!force && signature === lastSelectionSignature) return;
83
+ lastSelectionSignature = signature;
84
+ void dotnetRef.invokeMethodAsync('OnCanvasSelectionChanged', ids)
85
+ .catch(error => console.warn('[CanvasChatTaskSwitch] selection callback failed', error));
86
+ }
87
+
88
+ function startSelectionWatch() {
89
+ if (selectionTimer) return;
90
+ pushSelection(true);
91
+ selectionTimer = window.setInterval(() => pushSelection(false), 220);
92
+ }
93
+
94
+ function stopSelectionWatch() {
95
+ if (!selectionTimer) return;
96
+ window.clearInterval(selectionTimer);
97
+ selectionTimer = 0;
98
+ }
99
+
100
+ export function attach(ref) {
101
+ dotnetRef = ref;
102
+ if (attached) return;
103
+ attached = true;
104
+ document.addEventListener('keydown', onKeyDown, true);
105
+ document.addEventListener('click', onClick, true);
106
+ startSelectionWatch();
107
+ }
108
+
109
+ export function setMode(value) {
110
+ mode = value === 'task' ? 'task' : 'chat';
111
+ }
112
+
113
+ export function detach() {
114
+ if (!attached) return;
115
+ document.removeEventListener('keydown', onKeyDown, true);
116
+ document.removeEventListener('click', onClick, true);
117
+ stopSelectionWatch();
118
+ attached = false;
119
+ dotnetRef = null;
120
+ mode = 'chat';
121
+ lastSelectionSignature = '';
122
+ }
@@ -4707,7 +4707,11 @@
4707
4707
  large: Object.freeze({ tileMinWidth: 297, tileMinHeight: 189 })
4708
4708
  });
4709
4709
  const AUTOMATION_NODE_KIND_METADATA_KEY = 'AutomationNodeKind';
4710
- const AUTOMATION_NODE_ROLE_METADATA_KEY = 'AutomationNodeRole';
4710
+ const AUTOMATION_NODE_ROLE_METADATA_KEY = 'AutomationNodeRole';
4711
+ const AUTOMATION_PARENT_TASK_NODE_ID_METADATA_KEY = 'AutomationParentTaskNodeId';
4712
+ const CANVAS_DIRECTOR_STATUS_METADATA_KEY = 'CanvasDirectorStatus';
4713
+ const CANVAS_DIRECTOR_LAYOUT_MODE_METADATA_KEY = 'CanvasDirectorLayoutMode';
4714
+ const CANVAS_DIRECTOR_LAYOUT_VERSION_METADATA_KEY = 'CanvasDirectorLayoutVersion';
4711
4715
  const AUTOMATION_NODE_LABEL_METADATA_KEY = 'AutomationNodeLabel';
4712
4716
  const AUTOMATION_NODE_DESCRIPTION_METADATA_KEY = 'AutomationNodeDescription';
4713
4717
  const AUTOMATION_INFERRED_KIND_METADATA_KEY = 'AutomationInferredKind';
@@ -5847,6 +5851,10 @@
5847
5851
  return;
5848
5852
  }
5849
5853
 
5854
+ if (window.MindMapInteractions?.tryHandleReadableNodeWheelInZoomMode?.(module, event) === true) {
5855
+ return;
5856
+ }
5857
+
5850
5858
  if (shouldEditingWheelZoom(module, event)) {
5851
5859
  window.MindMapInteractions?.routeWheelEventToZoom?.(module, event);
5852
5860
  return;
@@ -7642,7 +7650,8 @@
7642
7650
  function isBusinessAutomationInternalFailureText(value) {
7643
7651
  const text = String(value || '');
7644
7652
  return /ConceptVerificationException|CALL target not found in registry|Concept IR|ans_0/i.test(text)
7645
- || (/^Error:/i.test(text.trim()) && /Exception/i.test(text));
7653
+ || (/^Error:/i.test(text.trim()) && /Exception/i.test(text))
7654
+ || /Error recovered|deterministic-fallback|Recovered from\s+[A-Za-z0-9_.]+Exception/i.test(text);
7646
7655
  }
7647
7656
 
7648
7657
  function cleanBusinessAutomationTooltipOutput(value, maxLength = Number.POSITIVE_INFINITY) {
@@ -7654,7 +7663,7 @@
7654
7663
  }
7655
7664
 
7656
7665
  if (isBusinessAutomationInternalFailureText(original)) {
7657
- return 'AI execution failed internally. Run Node again to use the recovered fallback output.';
7666
+ return 'AI execution was interrupted. Run this step again.';
7658
7667
  }
7659
7668
 
7660
7669
  const section = extractBusinessAutomationTooltipSection(raw, 'Findings:')
@@ -7717,6 +7726,74 @@
7717
7726
  : stripBusinessAutomationInstructionLabel(instruction);
7718
7727
  }
7719
7728
 
7729
+ function getBusinessAutomationCanvasBody(nodeModel, fallbackContent) {
7730
+ const status = getBusinessAutomationEffectiveRunStatus(nodeModel);
7731
+ const intentKind = getBusinessAutomationIntentKind(nodeModel).toLowerCase();
7732
+ const instruction = getBusinessAutomationInstructionText(nodeModel);
7733
+ const isKorean = /[\u1100-\u11ff\u3130-\u318f\uac00-\ud7af]/.test(instruction || String(fallbackContent || ''));
7734
+ const summary = cleanBusinessAutomationTooltipOutput(
7735
+ getAutomationMetadataValue(nodeModel, AUTOMATION_LAST_RUN_SUMMARY_METADATA_KEY, '')
7736
+ );
7737
+ const handoff = cleanBusinessAutomationTooltipOutput(
7738
+ getAutomationMetadataValue(nodeModel, AUTOMATION_LAST_OUTPUT_METADATA_KEY, '')
7739
+ );
7740
+ const error = compactBusinessAutomationTooltipText(
7741
+ getAutomationMetadataValue(nodeModel, 'AutomationLastRunError', ''),
7742
+ 1400
7743
+ );
7744
+
7745
+ if (intentKind === 'human-review' && status === 'waiting-user') {
7746
+ return { text: String(fallbackContent || ''), placeholder: false, mode: 'review' };
7747
+ }
7748
+
7749
+ const result = handoff || summary;
7750
+ if (result && !['planning', 'running', 'pending'].includes(status)) {
7751
+ return { text: result, placeholder: false, mode: 'result' };
7752
+ }
7753
+
7754
+ if (status === 'failed' || status === 'blocked') {
7755
+ return {
7756
+ text: error || (isKorean ? '작업을 완료하지 못했습니다.' : 'This step could not be completed.'),
7757
+ placeholder: true,
7758
+ mode: 'error'
7759
+ };
7760
+ }
7761
+
7762
+ if (status === 'planning') {
7763
+ return {
7764
+ text: isKorean ? '작업 단계를 구성하고 있습니다…' : 'Building the work steps…',
7765
+ placeholder: true,
7766
+ mode: 'planning'
7767
+ };
7768
+ }
7769
+
7770
+ if (status === 'running') {
7771
+ return {
7772
+ text: isKorean ? '결과를 만드는 중입니다…' : 'Producing the result…',
7773
+ placeholder: true,
7774
+ mode: 'running'
7775
+ };
7776
+ }
7777
+
7778
+ if (status === 'pending') {
7779
+ return {
7780
+ text: isKorean ? '앞 단계의 결과를 기다리고 있습니다.' : 'Waiting for the previous result.',
7781
+ placeholder: true,
7782
+ mode: 'pending'
7783
+ };
7784
+ }
7785
+
7786
+ if (result) {
7787
+ return { text: result, placeholder: false, mode: 'result' };
7788
+ }
7789
+
7790
+ return {
7791
+ text: isKorean ? '아직 결과가 없습니다.' : 'No result yet.',
7792
+ placeholder: true,
7793
+ mode: 'idle'
7794
+ };
7795
+ }
7796
+
7720
7797
  function getBusinessAutomationForwardEdgeCount(nodeModel) {
7721
7798
  return readBusinessAutomationEdges(nodeModel)
7722
7799
  .filter(edge => normalizeBusinessAutomationHint(edge.targetPinId) !== 'context')
@@ -9012,14 +9089,43 @@
9012
9089
  .replace(/\s+/g, '-');
9013
9090
  }
9014
9091
 
9092
+ function getBusinessAutomationDirectorStatus(nodeModel) {
9093
+ return getAutomationMetadataValue(nodeModel, CANVAS_DIRECTOR_STATUS_METADATA_KEY, '')
9094
+ .toLowerCase()
9095
+ .replace(/\s+/g, '-');
9096
+ }
9097
+
9098
+ function isBusinessAutomationGeneratedPendingNode(nodeModel) {
9099
+ const role = getBusinessAutomationNodeRole(nodeModel);
9100
+ const parentTaskNodeId = getAutomationMetadataValue(nodeModel, AUTOMATION_PARENT_TASK_NODE_ID_METADATA_KEY, '');
9101
+ const runState = getBusinessAutomationRunState(nodeModel);
9102
+ const runStatus = getBusinessAutomationRunStatus(nodeModel);
9103
+ const directorStatus = getBusinessAutomationDirectorStatus(nodeModel);
9104
+ return !!parentTaskNodeId
9105
+ && (role === 'job' || role === 'report')
9106
+ && (runState === 'idle' || runState === 'planned')
9107
+ && runStatus === 'not-run'
9108
+ && (directorStatus === 'todo' || directorStatus === 'planned');
9109
+ }
9110
+
9015
9111
  function getBusinessAutomationEffectiveRunStatus(nodeModel) {
9016
- return getBusinessAutomationRunState(nodeModel) === 'running'
9017
- ? 'running'
9018
- : getBusinessAutomationRunStatus(nodeModel);
9112
+ const runState = getBusinessAutomationRunState(nodeModel);
9113
+ if (runState === 'planning' || runState === 'running' || runState === 'waiting-user' || runState === 'blocked') {
9114
+ return runState;
9115
+ }
9116
+ if (isBusinessAutomationGeneratedPendingNode(nodeModel)) {
9117
+ return 'pending';
9118
+ }
9119
+ const runStatus = getBusinessAutomationRunStatus(nodeModel);
9120
+ if (runState === 'completed' && runStatus === 'not-run') {
9121
+ return 'completed';
9122
+ }
9123
+ return runStatus;
9019
9124
  }
9020
9125
 
9021
9126
  function hasBusinessAutomationResultOutput(nodeModel) {
9022
- if (getBusinessAutomationEffectiveRunStatus(nodeModel) === 'running') {
9127
+ const status = getBusinessAutomationEffectiveRunStatus(nodeModel);
9128
+ if (status === 'planning' || status === 'running' || status === 'pending') {
9023
9129
  return false;
9024
9130
  }
9025
9131
 
@@ -9048,15 +9154,24 @@
9048
9154
  case 'prepared': return 'Spec only';
9049
9155
  case 'needs-review': return 'Review needed';
9050
9156
  case 'error-recovered': return 'Error recovered';
9157
+ case 'failed': return 'Failed';
9158
+ case 'blocked': return 'Blocked';
9159
+ case 'completed': return 'Completed';
9051
9160
  case 'not-run': return 'Not run';
9052
9161
  default: return 'Unknown';
9053
9162
  }
9054
9163
  }
9055
9164
 
9056
9165
  function getBusinessAutomationEffectiveRunStatusLabel(nodeModel) {
9057
- return getBusinessAutomationRunState(nodeModel) === 'running'
9058
- ? 'Running'
9059
- : getBusinessAutomationRunStatusLabel(nodeModel);
9166
+ switch (getBusinessAutomationEffectiveRunStatus(nodeModel)) {
9167
+ case 'planning': return 'Planning';
9168
+ case 'running': return 'Running';
9169
+ case 'pending': return 'Queued';
9170
+ case 'waiting-user': return 'Waiting for you';
9171
+ case 'blocked': return 'Blocked';
9172
+ case 'completed': return 'Completed';
9173
+ default: return getBusinessAutomationRunStatusLabel(nodeModel);
9174
+ }
9060
9175
  }
9061
9176
 
9062
9177
  function createBusinessAutomationStatusBadge(nodeModel) {
@@ -9073,6 +9188,8 @@
9073
9188
  const partial = getAutomationMetadataValue(nodeModel, AUTOMATION_LAST_RUN_IS_PARTIAL_METADATA_KEY, 'false');
9074
9189
  const toolsUsed = getAutomationMetadataValue(nodeModel, AUTOMATION_LAST_RUN_TOOLS_USED_METADATA_KEY, '');
9075
9190
  const toolWarnings = getAutomationMetadataValue(nodeModel, AUTOMATION_LAST_RUN_TOOL_WARNINGS_METADATA_KEY, '');
9191
+ const layoutMode = getAutomationMetadataValue(nodeModel, CANVAS_DIRECTOR_LAYOUT_MODE_METADATA_KEY, '');
9192
+ const layoutVersion = getAutomationMetadataValue(nodeModel, CANVAS_DIRECTOR_LAYOUT_VERSION_METADATA_KEY, '');
9076
9193
  const badge = document.createElement('div');
9077
9194
  badge.className = `map-node-memo__automation-status is-${status}`;
9078
9195
  badge.dataset.automationRunState = runState;
@@ -9084,17 +9201,23 @@
9084
9201
  `Evidence URLs: ${evidenceCount}`,
9085
9202
  `Fallback: ${fallback}`,
9086
9203
  `Partial: ${partial}`,
9204
+ layoutMode ? `Layout: ${layoutMode}${layoutVersion ? ` (${layoutVersion})` : ''}` : '',
9087
9205
  toolWarnings ? `Tool warning: ${toolWarnings}` : ''
9088
9206
  ].filter(Boolean).join('\n');
9089
9207
 
9090
- const dot = document.createElement('span');
9091
- dot.className = status === 'running'
9092
- ? 'map-node-memo__automation-status-spinner'
9093
- : 'map-node-memo__automation-status-dot';
9208
+ const stateIcon = document.createElement('span');
9209
+ if (status === 'planning' || status === 'running') {
9210
+ stateIcon.className = 'map-node-memo__automation-status-spinner';
9211
+ } else if (runState === 'completed' || status === 'completed' || status === 'answered') {
9212
+ stateIcon.className = 'map-node-memo__automation-status-check';
9213
+ stateIcon.textContent = '✓';
9214
+ } else {
9215
+ stateIcon.className = 'map-node-memo__automation-status-dot';
9216
+ }
9094
9217
  const text = document.createElement('span');
9095
9218
  text.className = 'map-node-memo__automation-status-label';
9096
9219
  text.textContent = label;
9097
- badge.appendChild(dot);
9220
+ badge.appendChild(stateIcon);
9098
9221
  badge.appendChild(text);
9099
9222
  return badge;
9100
9223
  }
@@ -9486,6 +9609,14 @@
9486
9609
  .forEach(element => element.remove());
9487
9610
  Array.from(container.querySelectorAll('.map-node-memo__automation-status'))
9488
9611
  .forEach(element => element.remove());
9612
+ container.classList.remove(
9613
+ 'is-task-planning',
9614
+ 'is-task-running',
9615
+ 'is-task-pending',
9616
+ 'is-task-waiting',
9617
+ 'is-task-completed',
9618
+ 'is-task-blocked'
9619
+ );
9489
9620
 
9490
9621
  if (!isBusinessAutomationNode(nodeModel)) {
9491
9622
  applyBusinessAutomationTooltip(container, null);
@@ -9532,6 +9663,12 @@
9532
9663
  const automationRunState = getBusinessAutomationRunState(nodeModel);
9533
9664
  const automationRunStatus = getBusinessAutomationEffectiveRunStatus(nodeModel);
9534
9665
  const automationIsRunning = automationRunStatus === 'running' || automationRunState === 'running';
9666
+ container.classList.toggle('is-task-planning', automationRunStatus === 'planning');
9667
+ container.classList.toggle('is-task-running', automationRunStatus === 'running');
9668
+ container.classList.toggle('is-task-pending', automationRunStatus === 'pending');
9669
+ container.classList.toggle('is-task-waiting', automationRunStatus === 'waiting-user' || automationRunStatus === 'needs-review');
9670
+ container.classList.toggle('is-task-completed', automationRunState === 'completed');
9671
+ container.classList.toggle('is-task-blocked', automationRunStatus === 'blocked');
9535
9672
  container.dataset.automationRunState = automationRunState;
9536
9673
  container.dataset.automationInstruction = getBusinessAutomationInstructionText(nodeModel);
9537
9674
  container.dataset.automationLastRunSummary = automationIsRunning ? '' : cleanBusinessAutomationTooltipOutput(
@@ -24111,7 +24248,14 @@
24111
24248
  }
24112
24249
  disableEditorAssist(bodyTextarea);
24113
24250
  }
24114
- renderMemoBodyView(bodyView, nodeModel, content);
24251
+ const canvasBody = businessAutomation
24252
+ ? getBusinessAutomationCanvasBody(nodeModel, content)
24253
+ : { text: content, placeholder: false, mode: 'content' };
24254
+ if (bodyView) {
24255
+ bodyView.classList.toggle('is-automation-result-placeholder', !!canvasBody.placeholder);
24256
+ bodyView.dataset.automationBodyMode = canvasBody.mode || '';
24257
+ }
24258
+ renderMemoBodyView(bodyView, nodeModel, canvasBody.text);
24115
24259
  setMemoEditingState(memoEl, memoEl.classList.contains('is-editing'));
24116
24260
 
24117
24261
  renderMemoIconButton(iconButton, iconKey);
@@ -24648,6 +24792,7 @@
24648
24792
  getTextOverlayScrollSyncSelectors: getTextOverlayScrollSyncSelectors,
24649
24793
  getReadonlyTextOverlayMode: getReadonlyTextOverlayMode,
24650
24794
  rememberEditingScrollState: rememberEditingScrollState,
24795
+ syncEditingWheelScroll: syncEditingWheelScroll,
24651
24796
  refreshVisibleImageSources: refreshVisibleImageSources,
24652
24797
  restoreEditingScrollState: restoreEditingScrollState,
24653
24798
  setCssImageLoadingState: setCssImageLoadingState,
@@ -2122,7 +2122,7 @@ window.MindMapInteractions = (function () {
2122
2122
 
2123
2123
  const candidateIds = [];
2124
2124
  const seenIds = new Set();
2125
- const normalizedCellRadius = Math.max(0, Math.min(3, Math.round(Number(cellRadius || 1))));
2125
+ const normalizedCellRadius = Math.max(0, Math.min(3, Math.round(Number(cellRadius ?? 1))));
2126
2126
  const cellSize = Math.max(1, Number(module.GRID_CELL_SIZE || 500));
2127
2127
  const currentCellX = Math.floor(Number(point.x || 0) / cellSize);
2128
2128
  const currentCellY = Math.floor(Number(point.y || 0) / cellSize);
@@ -2152,7 +2152,7 @@ window.MindMapInteractions = (function () {
2152
2152
 
2153
2153
  function getHitTestCandidateNodeIds(module, point, options = {}) {
2154
2154
  if (!module?.nodeObjectsById || !point) return null;
2155
- const normalizedCellRadius = Math.max(0, Math.min(3, Math.round(Number(options.cellRadius || 1))));
2155
+ const normalizedCellRadius = Math.max(0, Math.min(3, Math.round(Number(options.cellRadius ?? 1))));
2156
2156
  module?.logicWorkerBridge?.primeHitTestCandidates?.(module, {
2157
2157
  point,
2158
2158
  cellRadius: normalizedCellRadius
@@ -3081,6 +3081,7 @@ window.MindMapInteractions = (function () {
3081
3081
 
3082
3082
  const DEFAULT_SCROLLABLE_SELECTORS = '.node-response, .note-content, .markdown-body, .prose, .note-textarea, .code-body, .code-content, .csv-table-scroll, .csv-table-scroll *, .pdf-content, .text-content, .file-content, .map-node-memo__body, .map-node-memo__body-view, pre, code';
3083
3083
  const DEFAULT_TEXT_CONTENT_SELECTORS = '.node-response, .code-body, .text-content, .markdown-body, .prose, .csv-table-scroll, .csv-table-cell';
3084
+ const ZOOM_MODE_READABLE_WHEEL_CONTENT_TYPES = new Set(['text', 'markdown', 'note', 'memo', 'code']);
3084
3085
 
3085
3086
  function getScrollableSelectors() {
3086
3087
  return window.MindMapCss3DManager?.getTextInteractionScrollableSelectors?.()
@@ -6722,6 +6723,64 @@ window.MindMapInteractions = (function () {
6722
6723
  return Math.abs(appliedDelta) > 0.01 || Math.abs(remainingDelta) > CTRL_WHEEL_SCROLL_EDGE_EPSILON;
6723
6724
  }
6724
6725
 
6726
+ function tryHandleReadableNodeWheelInZoomMode(module, e) {
6727
+ if (!module || !e || typeof e.target?.closest !== 'function') {
6728
+ return false;
6729
+ }
6730
+
6731
+ const wheelAnalysis = getWheelEventAnalysis(module, e);
6732
+ if (wheelAnalysis.isSyntheticTrackpadPinch === true ||
6733
+ shouldZoomFromWheelEvent(module, e, wheelAnalysis) !== true) {
6734
+ return false;
6735
+ }
6736
+
6737
+ const nodeElement = e.target.closest('[data-node-id]');
6738
+ const nodeId = String(nodeElement?.dataset?.nodeId || '').trim();
6739
+ const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
6740
+ const contentType = String(
6741
+ entry?.model?.contentType ||
6742
+ entry?.model?.ContentType ||
6743
+ nodeElement?.dataset?.contentType ||
6744
+ ''
6745
+ ).trim().toLowerCase();
6746
+ if (!nodeElement || !ZOOM_MODE_READABLE_WHEEL_CONTENT_TYPES.has(contentType)) {
6747
+ return false;
6748
+ }
6749
+
6750
+ const selectors = getScrollableSelectors();
6751
+ let scrollableEl = e.target.closest(selectors);
6752
+ if (!scrollableEl || !nodeElement.contains(scrollableEl)) {
6753
+ scrollableEl = nodeElement.querySelector(selectors);
6754
+ }
6755
+ if (!scrollableEl) {
6756
+ return false;
6757
+ }
6758
+
6759
+ const maxScrollTop = Math.max(0, Number(scrollableEl.scrollHeight || 0) - Number(scrollableEl.clientHeight || 0));
6760
+ if (maxScrollTop <= CTRL_WHEEL_SCROLL_EDGE_EPSILON) {
6761
+ return false;
6762
+ }
6763
+
6764
+ const deltaY = normalizeWheelDeltaY(e);
6765
+ if (!Number.isFinite(deltaY) || Math.abs(deltaY) <= 0.01) {
6766
+ return false;
6767
+ }
6768
+
6769
+ const currentScrollTop = Math.max(0, Number(scrollableEl.scrollTop || 0));
6770
+ const nextScrollTop = Math.min(maxScrollTop, Math.max(0, currentScrollTop + deltaY));
6771
+ if (Math.abs(nextScrollTop - currentScrollTop) > 0.01) {
6772
+ scrollableEl.scrollTop = nextScrollTop;
6773
+ window.MindMapTextOverlayV2?.syncReadonlySourceScroll?.(module, scrollableEl);
6774
+ window.MindMapCss3DManager?.syncEditingWheelScroll?.(module, scrollableEl);
6775
+ }
6776
+
6777
+ // Readable text owns the wheel while the pointer is over its scrollable body,
6778
+ // including at the top/bottom edge. Do not turn an edge-scroll into camera zoom.
6779
+ e.preventDefault();
6780
+ e.stopPropagation();
6781
+ return true;
6782
+ }
6783
+
6725
6784
  function tryHandleScrollableWheelEvent(module, e, options = {}) {
6726
6785
  const { fallbackToTrackpadPan = false } = options;
6727
6786
  const wheelTarget = e?.target;
@@ -6831,6 +6890,12 @@ window.MindMapInteractions = (function () {
6831
6890
  wheelAnalysis.isSyntheticTrackpadPinch === true ||
6832
6891
  shouldZoomFromWheelEvent(module, e, wheelAnalysis);
6833
6892
 
6893
+ if (shouldRouteWheelToZoom &&
6894
+ wheelAnalysis.isSyntheticTrackpadPinch !== true &&
6895
+ tryHandleReadableNodeWheelInZoomMode(module, e)) {
6896
+ return;
6897
+ }
6898
+
6834
6899
  if (shouldRouteWheelToZoom) {
6835
6900
  if (WHEEL_DEBUG) {
6836
6901
  if (!module._wheelDebug) {
@@ -7870,6 +7935,7 @@ window.MindMapInteractions = (function () {
7870
7935
  routeCtrlWheelEventToVerticalScroll: routeCtrlWheelEventToVerticalScroll,
7871
7936
  applyCtrlWheelVerticalScrollDelta: applyCtrlWheelVerticalScrollDelta,
7872
7937
  applyCtrlWheelToScrollableElement: applyCtrlWheelToScrollableElement,
7938
+ tryHandleReadableNodeWheelInZoomMode: tryHandleReadableNodeWheelInZoomMode,
7873
7939
  shouldZoomFromWheelEvent: shouldZoomFromWheelEvent,
7874
7940
  shouldTreatWheelAsZoom: shouldTreatWheelAsZoom,
7875
7941
  isTrackpadPinchGesture: isTrackpadPinchGesture,
@@ -3,6 +3,9 @@
3
3
  function createState() {
4
4
  return {
5
5
  boardId: '',
6
+ boardEpoch: 0,
7
+ engineGeneration: 0,
8
+ boardRevision: 0,
6
9
  nodes: new Map(),
7
10
  totalTextLikeCount: 0
8
11
  };
@@ -31,9 +34,39 @@ function normalizeNode(node) {
31
34
  };
32
35
  }
33
36
 
34
- function clearState(boardId) {
37
+ function normalizeOwnerToken(value) {
38
+ const number = Number(value || 0);
39
+ return Number.isFinite(number) && number > 0 ? Math.floor(number) : 0;
40
+ }
41
+
42
+ function normalizeBoardRevision(value) {
43
+ const number = Number(value || 0);
44
+ return Number.isFinite(number) && number >= 0 ? Math.floor(number) : 0;
45
+ }
46
+
47
+ function clearState(boardId, boardEpoch = 0, engineGeneration = 0, boardRevision = 0) {
35
48
  runtime = createState();
36
49
  runtime.boardId = normalizeBoardId(boardId);
50
+ runtime.boardEpoch = normalizeOwnerToken(boardEpoch);
51
+ runtime.engineGeneration = normalizeOwnerToken(engineGeneration);
52
+ runtime.boardRevision = normalizeBoardRevision(boardRevision);
53
+ }
54
+
55
+ function ownerMatches(message, requireRevision = true) {
56
+ if (normalizeBoardId(message?.boardId) !== runtime.boardId ||
57
+ normalizeOwnerToken(message?.boardEpoch) !== runtime.boardEpoch ||
58
+ normalizeOwnerToken(message?.engineGeneration) !== runtime.engineGeneration) {
59
+ return false;
60
+ }
61
+ return requireRevision !== true || normalizeBoardRevision(message?.boardRevision) === runtime.boardRevision;
62
+ }
63
+
64
+ function acceptMutationRevision(message) {
65
+ if (!ownerMatches(message, false)) return false;
66
+ const revision = normalizeBoardRevision(message?.boardRevision);
67
+ if (revision < runtime.boardRevision) return false;
68
+ runtime.boardRevision = revision;
69
+ return true;
37
70
  }
38
71
 
39
72
  function upsertNode(node) {
@@ -71,8 +104,8 @@ function removeNode(nodeId) {
71
104
  runtime.nodes.delete(normalizedId);
72
105
  }
73
106
 
74
- function rebuildBoard(boardId, nodes) {
75
- clearState(boardId);
107
+ function rebuildBoard(boardId, nodes, boardEpoch, engineGeneration, boardRevision) {
108
+ clearState(boardId, boardEpoch, engineGeneration, boardRevision);
76
109
  const sourceNodes = Array.isArray(nodes) ? nodes : [];
77
110
  for (let i = 0; i < sourceNodes.length; i++) {
78
111
  upsertNode(sourceNodes[i]);
@@ -81,7 +114,7 @@ function rebuildBoard(boardId, nodes) {
81
114
 
82
115
  function handleLodPlanQuery(message) {
83
116
  const boardId = normalizeBoardId(message.boardId);
84
- if (!boardId || boardId !== runtime.boardId) {
117
+ if (!boardId || !ownerMatches(message)) {
85
118
  return;
86
119
  }
87
120
 
@@ -110,6 +143,9 @@ function handleLodPlanQuery(message) {
110
143
  self.postMessage({
111
144
  type: 'LOD_PLAN_RESULT',
112
145
  boardId,
146
+ boardEpoch: runtime.boardEpoch,
147
+ engineGeneration: runtime.engineGeneration,
148
+ boardRevision: runtime.boardRevision,
113
149
  seq: Number(message.seq || 0),
114
150
  key: String(message.key || '').trim(),
115
151
  visibilityVersion: Number(message.visibilityVersion || 0),
@@ -131,18 +167,18 @@ self.onmessage = function (event) {
131
167
 
132
168
  switch (message.type) {
133
169
  case 'RESET_BOARD':
134
- clearState(message.boardId);
170
+ clearState(message.boardId, message.boardEpoch, message.engineGeneration, message.boardRevision);
135
171
  break;
136
172
  case 'REBUILD_BOARD':
137
- rebuildBoard(message.boardId, message.nodes);
173
+ rebuildBoard(message.boardId, message.nodes, message.boardEpoch, message.engineGeneration, message.boardRevision);
138
174
  break;
139
175
  case 'UPSERT_NODE':
140
- if (normalizeBoardId(message.boardId) === runtime.boardId) {
176
+ if (acceptMutationRevision(message)) {
141
177
  upsertNode(message.node);
142
178
  }
143
179
  break;
144
180
  case 'REMOVE_NODE':
145
- if (normalizeBoardId(message.boardId) === runtime.boardId) {
181
+ if (acceptMutationRevision(message)) {
146
182
  removeNode(message.nodeId);
147
183
  }
148
184
  break;