@mindexec/cli 0.2.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 (232) hide show
  1. package/README.md +275 -0
  2. package/codex-runtime.js +960 -0
  3. package/launch-bridge.cjs +162 -0
  4. package/package.json +61 -0
  5. package/port-guard.cjs +232 -0
  6. package/scripts/setup-tree-sitter-grammars.mjs +59 -0
  7. package/server.js +8422 -0
  8. package/start-bridge.bat +32 -0
  9. package/start-bridge.sh +81 -0
  10. package/tree-sitter-grammars/README.md +18 -0
  11. package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
  12. package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
  13. package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
  14. package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
  15. package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
  16. package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
  17. package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
  18. package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
  19. package/wwwroot/MindExecution.Web.styles.css +3 -0
  20. package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -0
  21. package/wwwroot/_content/MindExecution.Plugins.Directory/MindExecution.Plugins.Directory.u7utcng611.bundle.scp.css +7 -0
  22. package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
  23. package/wwwroot/_content/MindExecution.Plugins.Directory/directory-manager.js +202 -0
  24. package/wwwroot/_content/MindExecution.Plugins.Directory/exampleJsInterop.js +6 -0
  25. package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -0
  26. package/wwwroot/_content/MindExecution.Shared/MindExecution.Shared.wsano1j4wp.bundle.scp.css +4 -0
  27. package/wwwroot/_content/MindExecution.Shared/css/admin-dashboard.css +559 -0
  28. package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -0
  29. package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +2936 -0
  30. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
  31. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
  32. package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +359 -0
  33. package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1721 -0
  34. package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -0
  35. package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +639 -0
  36. package/wwwroot/_content/MindExecution.Shared/js/helpers/InfiniteGridHelper.js +109 -0
  37. package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -0
  38. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +7982 -0
  39. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
  40. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +15803 -0
  41. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -0
  42. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1430 -0
  43. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
  44. package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +260 -0
  45. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7640 -0
  46. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -0
  47. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9923 -0
  48. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +977 -0
  49. package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1431 -0
  50. package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +1716 -0
  51. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +553 -0
  52. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4541 -0
  53. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +489 -0
  54. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
  55. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2075 -0
  56. package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +646 -0
  57. package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js +4323 -0
  58. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2260 -0
  59. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
  60. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +890 -0
  61. package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +594 -0
  62. package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +170 -0
  63. package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +788 -0
  64. package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +50 -0
  65. package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +188 -0
  66. package/wwwroot/_content/MindExecution.Shared/js/texture-worker.js +208 -0
  67. package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -0
  68. package/wwwroot/_content/MindExecution.Shared/js/titlebar-handler.js +191 -0
  69. package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +37 -0
  70. package/wwwroot/_content/MindExecution.Shared/js/token-worker.js +28 -0
  71. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +5626 -0
  72. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +7 -0
  73. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +9 -0
  74. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.ttf +0 -0
  75. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.woff2 +0 -0
  76. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.ttf +0 -0
  77. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.woff2 +0 -0
  78. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.ttf +0 -0
  79. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.woff2 +0 -0
  80. package/wwwroot/_content/MindExecution.Shared/models/all-MiniLM-L6-v2-quantized.onnx +0 -0
  81. package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -0
  82. package/wwwroot/_framework/Google.Protobuf.9h59ukbel7.dll +0 -0
  83. package/wwwroot/_framework/Markdig.d1j7v41cl1.dll +0 -0
  84. package/wwwroot/_framework/MessagePack.Annotations.l6qv48kgpt.dll +0 -0
  85. package/wwwroot/_framework/MessagePack.eqoptzx9d5.dll +0 -0
  86. package/wwwroot/_framework/Microsoft.AspNetCore.Authorization.k7dsih5y5g.dll +0 -0
  87. package/wwwroot/_framework/Microsoft.AspNetCore.Components.6nyje9sa0g.dll +0 -0
  88. package/wwwroot/_framework/Microsoft.AspNetCore.Components.Authorization.iycd6unprw.dll +0 -0
  89. package/wwwroot/_framework/Microsoft.AspNetCore.Components.Web.487u3twia4.dll +0 -0
  90. package/wwwroot/_framework/Microsoft.AspNetCore.Components.WebAssembly.d0gcnmlxxz.dll +0 -0
  91. package/wwwroot/_framework/Microsoft.AspNetCore.Metadata.h4yevl9adi.dll +0 -0
  92. package/wwwroot/_framework/Microsoft.CSharp.qrvp77qmhs.dll +0 -0
  93. package/wwwroot/_framework/Microsoft.Data.Sqlite.jdlxgv2jtg.dll +0 -0
  94. package/wwwroot/_framework/Microsoft.EntityFrameworkCore.4gjazp7kjf.dll +0 -0
  95. package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Abstractions.gocudnvz7b.dll +0 -0
  96. package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Relational.lt4rsvinuo.dll +0 -0
  97. package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Sqlite.69luj0fa9r.dll +0 -0
  98. package/wwwroot/_framework/Microsoft.Extensions.Caching.Abstractions.364t4jh3zz.dll +0 -0
  99. package/wwwroot/_framework/Microsoft.Extensions.Caching.Memory.izlxhpzosu.dll +0 -0
  100. package/wwwroot/_framework/Microsoft.Extensions.Configuration.8zq7hh41o7.dll +0 -0
  101. package/wwwroot/_framework/Microsoft.Extensions.Configuration.Abstractions.8if74zs6ea.dll +0 -0
  102. package/wwwroot/_framework/Microsoft.Extensions.Configuration.Json.duvlngw8i0.dll +0 -0
  103. package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.Abstractions.t2hh9kvx0o.dll +0 -0
  104. package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.n4tg99oy8l.dll +0 -0
  105. package/wwwroot/_framework/Microsoft.Extensions.DependencyModel.h0d06ixk3e.dll +0 -0
  106. package/wwwroot/_framework/Microsoft.Extensions.Logging.Abstractions.rl32bkx2sd.dll +0 -0
  107. package/wwwroot/_framework/Microsoft.Extensions.Logging.dlht1xei0t.dll +0 -0
  108. package/wwwroot/_framework/Microsoft.Extensions.Options.qeunebioml.dll +0 -0
  109. package/wwwroot/_framework/Microsoft.Extensions.Primitives.18cr6vnuuz.dll +0 -0
  110. package/wwwroot/_framework/Microsoft.IO.RecyclableMemoryStream.r915vovvw4.dll +0 -0
  111. package/wwwroot/_framework/Microsoft.IdentityModel.Abstractions.1ejljk3erv.dll +0 -0
  112. package/wwwroot/_framework/Microsoft.IdentityModel.JsonWebTokens.1596zr8gne.dll +0 -0
  113. package/wwwroot/_framework/Microsoft.IdentityModel.Logging.229uyvpgio.dll +0 -0
  114. package/wwwroot/_framework/Microsoft.IdentityModel.Tokens.9sibtajc9f.dll +0 -0
  115. package/wwwroot/_framework/Microsoft.JSInterop.17lq4j1j7g.dll +0 -0
  116. package/wwwroot/_framework/Microsoft.JSInterop.WebAssembly.ryia5gxiad.dll +0 -0
  117. package/wwwroot/_framework/Microsoft.ML.OnnxRuntime.w9deo1m5ss.dll +0 -0
  118. package/wwwroot/_framework/Microsoft.ML.Tokenizers.cm2vuv2z61.dll +0 -0
  119. package/wwwroot/_framework/Microsoft.NET.StringTools.3qbrf4v2ki.dll +0 -0
  120. package/wwwroot/_framework/MimeMapping.og9ys58ylm.dll +0 -0
  121. package/wwwroot/_framework/MindExecution.Core.1q1trifbuu.dll +0 -0
  122. package/wwwroot/_framework/MindExecution.Kernel.gwwc40sc45.dll +0 -0
  123. package/wwwroot/_framework/MindExecution.Plugins.Admin.0jgrn1sckv.dll +0 -0
  124. package/wwwroot/_framework/MindExecution.Plugins.Business.13mme2qcag.dll +0 -0
  125. package/wwwroot/_framework/MindExecution.Plugins.Concept.dfp2mdt45q.dll +0 -0
  126. package/wwwroot/_framework/MindExecution.Plugins.Directory.3w4t6n3se0.dll +0 -0
  127. package/wwwroot/_framework/MindExecution.Plugins.PlanMaster.s0qpntz420.dll +0 -0
  128. package/wwwroot/_framework/MindExecution.Plugins.YouTube.iu11fq8d16.dll +0 -0
  129. package/wwwroot/_framework/MindExecution.Shared.7j27dcqnrc.dll +0 -0
  130. package/wwwroot/_framework/MindExecution.Web.pq1ty8ov2v.dll +0 -0
  131. package/wwwroot/_framework/Newtonsoft.Json.a56zs13vug.dll +0 -0
  132. package/wwwroot/_framework/SQLitePCLRaw.batteries_v2.rrd1nzawpp.dll +0 -0
  133. package/wwwroot/_framework/SQLitePCLRaw.core.1dxloztpfz.dll +0 -0
  134. package/wwwroot/_framework/SQLitePCLRaw.provider.e_sqlite3.oekyzl53i1.dll +0 -0
  135. package/wwwroot/_framework/Supabase.Core.s1pkj4aj0l.dll +0 -0
  136. package/wwwroot/_framework/Supabase.Functions.qz4nu782sg.dll +0 -0
  137. package/wwwroot/_framework/Supabase.Gotrue.twah27pkik.dll +0 -0
  138. package/wwwroot/_framework/Supabase.Postgrest.gmuuv369ih.dll +0 -0
  139. package/wwwroot/_framework/Supabase.Realtime.ox3kchdy3w.dll +0 -0
  140. package/wwwroot/_framework/Supabase.Storage.fnjnepaowr.dll +0 -0
  141. package/wwwroot/_framework/Supabase.azmaw5pgcz.dll +0 -0
  142. package/wwwroot/_framework/System.Collections.Concurrent.y1zmvuyipi.dll +0 -0
  143. package/wwwroot/_framework/System.Collections.Immutable.ug3j698qms.dll +0 -0
  144. package/wwwroot/_framework/System.Collections.NonGeneric.h66hj3863h.dll +0 -0
  145. package/wwwroot/_framework/System.Collections.Specialized.umr3y27ntj.dll +0 -0
  146. package/wwwroot/_framework/System.Collections.x53e19vfsj.dll +0 -0
  147. package/wwwroot/_framework/System.ComponentModel.Annotations.tz6gnt4ebt.dll +0 -0
  148. package/wwwroot/_framework/System.ComponentModel.Primitives.j7tiphu4rg.dll +0 -0
  149. package/wwwroot/_framework/System.ComponentModel.TypeConverter.ujlztox1gx.dll +0 -0
  150. package/wwwroot/_framework/System.ComponentModel.x9xz0ojfb6.dll +0 -0
  151. package/wwwroot/_framework/System.Console.ijzpqmj7ne.dll +0 -0
  152. package/wwwroot/_framework/System.Data.Common.1r0sqffq1p.dll +0 -0
  153. package/wwwroot/_framework/System.Diagnostics.DiagnosticSource.9upoqwq09o.dll +0 -0
  154. package/wwwroot/_framework/System.Diagnostics.Process.m99azzntjm.dll +0 -0
  155. package/wwwroot/_framework/System.Diagnostics.TraceSource.pl7wv26myr.dll +0 -0
  156. package/wwwroot/_framework/System.Diagnostics.Tracing.crlhfx6tut.dll +0 -0
  157. package/wwwroot/_framework/System.Drawing.Primitives.22e4y9ikq9.dll +0 -0
  158. package/wwwroot/_framework/System.Drawing.mi7d8hwowb.dll +0 -0
  159. package/wwwroot/_framework/System.Formats.Asn1.jx23sjiqnn.dll +0 -0
  160. package/wwwroot/_framework/System.IO.Compression.6fyoii3uej.dll +0 -0
  161. package/wwwroot/_framework/System.IO.Pipelines.vg77t4cd4d.dll +0 -0
  162. package/wwwroot/_framework/System.IdentityModel.Tokens.Jwt.t67es60z5b.dll +0 -0
  163. package/wwwroot/_framework/System.Linq.1bkoxlqgmq.dll +0 -0
  164. package/wwwroot/_framework/System.Linq.Expressions.24xqiypwdt.dll +0 -0
  165. package/wwwroot/_framework/System.Linq.Queryable.hvd01d6rsa.dll +0 -0
  166. package/wwwroot/_framework/System.Memory.8dx3lwgym4.dll +0 -0
  167. package/wwwroot/_framework/System.Net.Http.Json.3mhdm9l1rf.dll +0 -0
  168. package/wwwroot/_framework/System.Net.Http.eitrz660my.dll +0 -0
  169. package/wwwroot/_framework/System.Net.NetworkInformation.3pkuofcv9r.dll +0 -0
  170. package/wwwroot/_framework/System.Net.Ping.8clj5pklrp.dll +0 -0
  171. package/wwwroot/_framework/System.Net.Primitives.qrp4wcjz1p.dll +0 -0
  172. package/wwwroot/_framework/System.Net.WebSockets.Client.2u6pv01g69.dll +0 -0
  173. package/wwwroot/_framework/System.Net.WebSockets.qp6u31zvm5.dll +0 -0
  174. package/wwwroot/_framework/System.Numerics.Tensors.0c7z4mt3on.dll +0 -0
  175. package/wwwroot/_framework/System.Numerics.Vectors.kc7ufp2j4l.dll +0 -0
  176. package/wwwroot/_framework/System.ObjectModel.qv82fot1ib.dll +0 -0
  177. package/wwwroot/_framework/System.Private.CoreLib.rkafq04oma.dll +0 -0
  178. package/wwwroot/_framework/System.Private.Uri.t9542hmr6j.dll +0 -0
  179. package/wwwroot/_framework/System.Private.Xml.Linq.n8n3ptrbwu.dll +0 -0
  180. package/wwwroot/_framework/System.Private.Xml.rxd3tytisn.dll +0 -0
  181. package/wwwroot/_framework/System.Reactive.t3fuon548l.dll +0 -0
  182. package/wwwroot/_framework/System.Reflection.Emit.9tjhp6y0j3.dll +0 -0
  183. package/wwwroot/_framework/System.Reflection.Emit.ILGeneration.stxyk8zoo1.dll +0 -0
  184. package/wwwroot/_framework/System.Reflection.Emit.Lightweight.6xrd5v8vg0.dll +0 -0
  185. package/wwwroot/_framework/System.Reflection.Primitives.wgn8fpwwvv.dll +0 -0
  186. package/wwwroot/_framework/System.Runtime.InteropServices.JavaScript.sliym526xh.dll +0 -0
  187. package/wwwroot/_framework/System.Runtime.InteropServices.RuntimeInformation.oji7zut14z.dll +0 -0
  188. package/wwwroot/_framework/System.Runtime.InteropServices.te07xr2we9.dll +0 -0
  189. package/wwwroot/_framework/System.Runtime.Intrinsics.507y4h8nzq.dll +0 -0
  190. package/wwwroot/_framework/System.Runtime.Loader.v7gk4bse0k.dll +0 -0
  191. package/wwwroot/_framework/System.Runtime.Numerics.eqy5xjv3nd.dll +0 -0
  192. package/wwwroot/_framework/System.Runtime.Serialization.Formatters.zpkrub8lab.dll +0 -0
  193. package/wwwroot/_framework/System.Runtime.Serialization.Primitives.vhkpnbxjip.dll +0 -0
  194. package/wwwroot/_framework/System.Runtime.jn319d5nyg.dll +0 -0
  195. package/wwwroot/_framework/System.Security.Claims.0ztig1q9vo.dll +0 -0
  196. package/wwwroot/_framework/System.Security.Cryptography.vttizqc9ho.dll +0 -0
  197. package/wwwroot/_framework/System.Text.Encoding.Extensions.utdd47ny8f.dll +0 -0
  198. package/wwwroot/_framework/System.Text.Encodings.Web.wah8r1zoe0.dll +0 -0
  199. package/wwwroot/_framework/System.Text.Json.kxlfxj0wrs.dll +0 -0
  200. package/wwwroot/_framework/System.Text.RegularExpressions.dbqn58klox.dll +0 -0
  201. package/wwwroot/_framework/System.Threading.42ao9vi047.dll +0 -0
  202. package/wwwroot/_framework/System.Threading.Channels.hfa7j0uv2w.dll +0 -0
  203. package/wwwroot/_framework/System.Threading.Thread.caul0pdqul.dll +0 -0
  204. package/wwwroot/_framework/System.Transactions.Local.fimi2hamzo.dll +0 -0
  205. package/wwwroot/_framework/System.Web.HttpUtility.gq8yz50p2e.dll +0 -0
  206. package/wwwroot/_framework/System.Xml.Linq.kitin4zjoj.dll +0 -0
  207. package/wwwroot/_framework/System.Xml.ReaderWriter.kzvw3qgxb0.dll +0 -0
  208. package/wwwroot/_framework/System.Xml.XDocument.c539ki6cuq.dll +0 -0
  209. package/wwwroot/_framework/System.m05i39uvk9.dll +0 -0
  210. package/wwwroot/_framework/Websocket.Client.vapounvmnl.dll +0 -0
  211. package/wwwroot/_framework/blazor.boot.json +305 -0
  212. package/wwwroot/_framework/blazor.webassembly.js +1 -0
  213. package/wwwroot/_framework/dotnet.js +4 -0
  214. package/wwwroot/_framework/dotnet.native.vz0adxojrz.wasm +0 -0
  215. package/wwwroot/_framework/dotnet.native.xsn1d6x2kd.js +16 -0
  216. package/wwwroot/_framework/dotnet.runtime.dstopyvqzi.js +4 -0
  217. package/wwwroot/_framework/icudt_CJK.tjcz0u77k5.dat +0 -0
  218. package/wwwroot/_framework/icudt_EFIGS.tptq2av103.dat +0 -0
  219. package/wwwroot/_framework/icudt_no_CJK.lfu7j35m59.dat +0 -0
  220. package/wwwroot/_framework/netstandard.0xet7jg7ky.dll +0 -0
  221. package/wwwroot/_headers +40 -0
  222. package/wwwroot/_redirects +1 -0
  223. package/wwwroot/appsettings.json +71 -0
  224. package/wwwroot/icon-192.png +0 -0
  225. package/wwwroot/icon-512.png +0 -0
  226. package/wwwroot/index.html +710 -0
  227. package/wwwroot/js/marketing-tool.js +180 -0
  228. package/wwwroot/manifest.webmanifest +22 -0
  229. package/wwwroot/robots.txt +4 -0
  230. package/wwwroot/service-worker-assets.js +857 -0
  231. package/wwwroot/service-worker.js +33 -0
  232. package/wwwroot/sitemap.xml +27 -0
@@ -0,0 +1,788 @@
1
+ // File: X:\Dev@Work\MindExecution\wwwroot\js\plan-master.js
2
+ // PlanAgent 3D graph agent surface (copied from code-master.js)
3
+ (function () {
4
+ // Module instance storage
5
+ let moduleInstance = null;
6
+ let pendingSettings = null;
7
+
8
+ // PlanMaster module class (kept for backward compatibility)
9
+ class PlanMasterModule {
10
+ constructor() {
11
+ // --- 3D rendering state ---
12
+ this.scene = null;
13
+ this.camera = null;
14
+ this.renderer = null;
15
+ this.cssRenderer = null;
16
+
17
+ // --- Blazor and DOM references ---
18
+ this.dotNetHelper = null;
19
+ this.container = null;
20
+
21
+ // --- Animation state ---
22
+ this.animationFrameId = null;
23
+
24
+ // --- Node management ---
25
+ this.nodeContentTargets = {};
26
+ this.nodeElements = {};
27
+ this.nodeObjectsById = new Map();
28
+
29
+ // --- Interaction state ---
30
+ this.isPanning = false;
31
+ this.lastMousePos = { x: 0, y: 0 };
32
+ this.targetZ = null;
33
+ this.targetX = null;
34
+ this.targetY = null;
35
+ this.isDraggingNode = false;
36
+ this.draggedNodeObject = null;
37
+
38
+ // --- Optimization state ---
39
+ this.isOptimizationActive = false;
40
+
41
+ // --- Text update state ---
42
+ this.latestMarkdownById = new Map();
43
+ this.pendingTextUpdates = new Map();
44
+ this.isTextUpdateScheduled = false;
45
+ this.throttledParseFlags = new Map();
46
+
47
+ // --- Theme management ---
48
+ this.currentThemeName = null;
49
+ this.currentThemeObject = null;
50
+
51
+ // --- Grid snapping ---
52
+ this.GRID_SIZE = 5;
53
+
54
+ // --- Bound event handlers ---
55
+ this.boundOnMouseDown = this.onMouseDown.bind(this);
56
+ this.boundOnMouseMove = this.onMouseMove.bind(this);
57
+ this.boundOnMouseUp = this.onMouseUp.bind(this);
58
+ this.boundOnContainerClick = this.onContainerClick.bind(this);
59
+ this.boundOnKeyDown = this.onKeyDown.bind(this);
60
+ this.boundOnContextMenu = this.onContextMenu.bind(this);
61
+ this.boundOnWheel = this.onWheel.bind(this);
62
+ this.boundOnResize = this.onResize.bind(this);
63
+ }
64
+
65
+ // Grid snapping utils
66
+ snapToGrid(value) {
67
+ return Math.floor(value / this.GRID_SIZE) * this.GRID_SIZE;
68
+ }
69
+ snapToGridY(value) {
70
+ return Math.ceil(value / this.GRID_SIZE) * this.GRID_SIZE;
71
+ }
72
+
73
+ // Enable optimization
74
+ activateOptimization() {
75
+ if (!this.isOptimizationActive) {
76
+ this.isOptimizationActive = true;
77
+ try {
78
+ this.container.querySelectorAll('.map-node-bubble').forEach(n => n.classList.add('optimizing-transform'));
79
+ } catch { }
80
+ }
81
+ }
82
+
83
+ // Disable optimization
84
+ deactivateOptimization() {
85
+ if (this.isOptimizationActive) {
86
+ this.isOptimizationActive = false;
87
+ try {
88
+ this.container.querySelectorAll('.map-node-bubble').forEach(n => n.classList.remove('optimizing-transform'));
89
+ } catch { }
90
+ }
91
+ }
92
+
93
+ // Ensure THREE and CSS3D are loaded
94
+ ensureThree() {
95
+ const hasThree = typeof globalThis.THREE !== 'undefined';
96
+ const hasCSS3D = typeof globalThis.CSS3DRenderer !== 'undefined';
97
+ if (!hasThree) {
98
+ console.error('[plan-master.js] THREE not loaded');
99
+ return false;
100
+ }
101
+ if (!hasCSS3D) {
102
+ console.error('[plan-master.js] CSS3DRenderer not loaded');
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+
108
+ resolveThemeNameFromGridType(gridType) {
109
+ const map = {
110
+ space3d: 'Space3D',
111
+ spirit: 'SpiritFlow',
112
+ default: 'XYGrid',
113
+ dot: 'SpatialGrid2D'
114
+ };
115
+ const key = String(gridType || 'dot').toLowerCase();
116
+ return map[key] || 'SpatialGrid2D';
117
+ }
118
+
119
+ resolveThemeFromGeneralSettings() {
120
+ try {
121
+ const raw = localStorage.getItem('GeneralSettings');
122
+ if (!raw) {
123
+ return 'SpatialGrid2D';
124
+ }
125
+
126
+ const settings = JSON.parse(raw);
127
+ return this.resolveThemeNameFromGridType(settings?.gridType);
128
+ } catch {
129
+ return 'SpatialGrid2D';
130
+ }
131
+ }
132
+
133
+ applySettings(settings) {
134
+ if (!settings || typeof settings !== 'object') {
135
+ this.setBackgroundTheme(this.resolveThemeFromGeneralSettings());
136
+ return;
137
+ }
138
+
139
+ if (settings.gridType) {
140
+ this.setBackgroundTheme(this.resolveThemeNameFromGridType(settings.gridType));
141
+ } else {
142
+ this.setBackgroundTheme(this.resolveThemeFromGeneralSettings());
143
+ }
144
+ }
145
+
146
+ // --- Event handlers ---
147
+
148
+ onMouseDown(e) {
149
+ if (e.button === 1 || e.button === 2 || (e.button === 0 && e.ctrlKey)) {
150
+ this.isPanning = true;
151
+ this.lastMousePos = { x: e.clientX, y: e.clientY };
152
+ this.container.style.cursor = 'grabbing';
153
+ e.preventDefault();
154
+ this.activateOptimization();
155
+ window.addEventListener('mousemove', this.boundOnMouseMove);
156
+ window.addEventListener('mouseup', this.boundOnMouseUp);
157
+ }
158
+ }
159
+
160
+ onMouseMove(e) {
161
+ if (this.isDraggingNode && this.draggedNodeObject) {
162
+ const dx = e.clientX - this.lastMousePos.x;
163
+ const dy = e.clientY - this.lastMousePos.y;
164
+ this.lastMousePos = { x: e.clientX, y: e.clientY };
165
+ const moveFactor = this.camera.position.z / 1200;
166
+ this.draggedNodeObject.position.x += dx * moveFactor;
167
+ this.draggedNodeObject.position.y -= dy * moveFactor;
168
+ return;
169
+ }
170
+ if (!this.isPanning) return;
171
+ const dx2 = e.clientX - this.lastMousePos.x;
172
+ const dy2 = e.clientY - this.lastMousePos.y;
173
+ this.lastMousePos = { x: e.clientX, y: e.clientY };
174
+ const panFactor = 0.002 * this.camera.position.z;
175
+ this.targetX -= dx2 * panFactor;
176
+ this.targetY += dy2 * panFactor;
177
+ }
178
+
179
+ onMouseUp(e) {
180
+ if (this.isDraggingNode && this.draggedNodeObject) {
181
+ // Apply grid snapping after drag ends
182
+ this.draggedNodeObject.position.x = this.snapToGrid(this.draggedNodeObject.position.x);
183
+ this.draggedNodeObject.position.y = this.snapToGridY(this.draggedNodeObject.position.y);
184
+
185
+ const finalNodeId = this.draggedNodeObject.element?.dataset?.nodeId;
186
+ const finalPosition = this.draggedNodeObject.position;
187
+ if (finalNodeId && this.dotNetHelper) {
188
+ this.dotNetHelper.invokeMethodAsync('UpdateNodePosition', finalNodeId, finalPosition.x, finalPosition.y);
189
+ }
190
+ this.isDraggingNode = false;
191
+ this.draggedNodeObject = null;
192
+ window.removeEventListener('mousemove', this.boundOnMouseMove);
193
+ window.removeEventListener('mouseup', this.boundOnMouseUp);
194
+ }
195
+ if (this.isPanning) {
196
+ this.isPanning = false;
197
+ this.container.style.cursor = 'default';
198
+ // Align camera position to grid after panning ends
199
+ this.targetX = this.snapToGrid(this.camera.position.x);
200
+ this.targetY = this.snapToGridY(this.camera.position.y);
201
+ window.removeEventListener('mousemove', this.boundOnMouseMove);
202
+ window.removeEventListener('mouseup', this.boundOnMouseUp);
203
+ }
204
+ }
205
+
206
+ onContainerClick(e) {
207
+ if (e.button === 0) {
208
+ if (!this.isPanning && !this.isDraggingNode) {
209
+ if (this.dotNetHelper) {
210
+ this.dotNetHelper.invokeMethodAsync('SelectNodeInBlazor', null);
211
+ }
212
+
213
+ // [Modified] Use blurElement helper to clear focus from text inputs
214
+ if (document.activeElement && (document.activeElement.tagName === 'TEXTAREA' || document.activeElement.tagName === 'INPUT')) {
215
+ // document.activeElement.blur(); // (old)
216
+ window.blurElement(document.activeElement); // (new)
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ onKeyDown(e) {
223
+ if (!this.dotNetHelper) return;
224
+ // Enter: move focus to the global textarea
225
+ if (e.key === 'Enter') {
226
+ const t = e.target;
227
+ const isInputFocused = t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.tagName === 'SELECT' || t.isContentEditable);
228
+ if (!isInputFocused) {
229
+ const textarea = document.getElementById('global-input-textarea');
230
+ if (textarea) {
231
+ textarea.focus();
232
+ e.preventDefault();
233
+ return;
234
+ }
235
+ }
236
+ if (t && t.id === 'global-input-textarea' && !e.shiftKey) {
237
+ return;
238
+ }
239
+ }
240
+ const target = e.target;
241
+ if (target) {
242
+ const tagName = target.tagName;
243
+ if (tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT' || target.isContentEditable) {
244
+ return;
245
+ }
246
+ }
247
+ const panFactor = 0.002 * this.camera.position.z;
248
+ const moveAmount = 80 * panFactor;
249
+ let handled = false;
250
+ switch (e.key) {
251
+ case 'ArrowUp':
252
+ this.camera.position.y += moveAmount;
253
+ this.targetY += moveAmount;
254
+ handled = true;
255
+ break;
256
+ case 'ArrowDown':
257
+ this.camera.position.y -= moveAmount;
258
+ this.targetY -= moveAmount;
259
+ handled = true;
260
+ break;
261
+ case 'ArrowLeft':
262
+ this.camera.position.x -= moveAmount;
263
+ this.targetX -= moveAmount;
264
+ handled = true;
265
+ break;
266
+ case 'ArrowRight':
267
+ this.camera.position.x += moveAmount;
268
+ this.targetX += moveAmount;
269
+ handled = true;
270
+ break;
271
+ case 'Delete':
272
+ if (this.dotNetHelper) {
273
+ this.dotNetHelper.invokeMethodAsync('DeleteSelectedNodeFromJs');
274
+ }
275
+ handled = true;
276
+ break;
277
+ }
278
+ if (handled) {
279
+ e.preventDefault();
280
+ this.activateOptimization();
281
+ }
282
+ }
283
+
284
+ onContextMenu(e) {
285
+ e.preventDefault();
286
+ }
287
+
288
+ onWheel(e) {
289
+ e.preventDefault();
290
+ this.activateOptimization();
291
+ const mouse = {
292
+ x: (e.clientX / this.container.clientWidth) * 2 - 1,
293
+ y: -(e.clientY / this.container.clientHeight) * 2 + 1
294
+ };
295
+ const vfov = (this.camera.fov * Math.PI) / 180;
296
+ const viewHeight = 2 * Math.tan(vfov / 2) * this.camera.position.z;
297
+ const viewWidth = viewHeight * this.camera.aspect;
298
+ const worldMouseX = this.camera.position.x + (mouse.x * viewWidth) / 2;
299
+ const worldMouseY = this.camera.position.y + (mouse.y * viewHeight) / 2;
300
+ const prevZ = this.camera.position.z;
301
+ const zoomSensitivity = 0.003;
302
+ const zoomAmount = e.deltaY * (this.camera.position.z * zoomSensitivity);
303
+ let newZ = this.camera.position.z + zoomAmount;
304
+ newZ = Math.max(200, Math.min(newZ, 6000));
305
+ const zoomRatio = newZ / prevZ;
306
+ this.camera.position.z = newZ;
307
+ this.targetZ = newZ;
308
+ const newX = worldMouseX - (worldMouseX - this.camera.position.x) * zoomRatio;
309
+ const newY = worldMouseY - (worldMouseY - this.camera.position.y) * zoomRatio;
310
+ this.camera.position.x = newX;
311
+ this.camera.position.y = newY;
312
+ this.targetX = newX;
313
+ this.targetY = newY;
314
+ }
315
+
316
+ onResize(e) {
317
+ if (!this.container || !this.renderer || !this.camera) return;
318
+ const width = this.container.clientWidth;
319
+ const height = this.container.clientHeight;
320
+ this.camera.aspect = width / height;
321
+ this.camera.updateProjectionMatrix();
322
+ this.renderer.setSize(width, height);
323
+ this.cssRenderer.setSize(width, height);
324
+ }
325
+
326
+ // --- Animation loop ---
327
+ animate() {
328
+ this.animationFrameId = requestAnimationFrame(() => this.animate());
329
+ const smoothingFactor = 0.25;
330
+ const dx = this.targetX - this.camera.position.x;
331
+ const dy = this.targetY - this.camera.position.y;
332
+ const dz = this.targetZ - this.camera.position.z;
333
+ const isCameraMoving = Math.abs(dx) > 0.01 || Math.abs(dy) > 0.01 || Math.abs(dz) > 0.01;
334
+ this.camera.position.x += dx * smoothingFactor;
335
+ this.camera.position.y += dy * smoothingFactor;
336
+ this.camera.position.z += dz * smoothingFactor;
337
+ if (this.isOptimizationActive && Math.abs(dx) < 0.1 && Math.abs(dy) < 0.1 && Math.abs(dz) < 0.1) {
338
+ this.deactivateOptimization();
339
+ }
340
+ if (this.currentThemeObject && typeof this.currentThemeObject.animate === 'function') {
341
+ const themeRunner = window.MindMapThemes?.runAnimationIfNeeded;
342
+ if (typeof themeRunner === 'function') {
343
+ themeRunner(this.currentThemeName, this.currentThemeObject, this.camera, {
344
+ isCameraMoving
345
+ });
346
+ } else {
347
+ this.currentThemeObject.animate(this.camera);
348
+ }
349
+ }
350
+ this.renderer.render(this.scene, this.camera);
351
+ this.cssRenderer.render(this.scene, this.camera);
352
+ }
353
+
354
+ // --- Text update processing ---
355
+ processPendingTextUpdates() {
356
+ this.isTextUpdateScheduled = false;
357
+ if (this.pendingTextUpdates.size === 0) return;
358
+ this.pendingTextUpdates.forEach((content, nodeId) => {
359
+ const elements = this.nodeElements[nodeId];
360
+ const contentEl = elements?.content || this.nodeContentTargets[nodeId];
361
+ if (!contentEl) return;
362
+ if (elements?.loading && elements.loading.style.display !== 'none') {
363
+ elements.loading.style.display = 'none';
364
+ }
365
+ try {
366
+ if (typeof marked !== 'undefined' && typeof marked.parse === 'function') {
367
+ contentEl.innerHTML = marked.parse(content || '');
368
+ } else {
369
+ contentEl.textContent = content || '';
370
+ }
371
+ } catch (e) {
372
+ console.error('[plan-master.js] Markdown parsing error:', e);
373
+ contentEl.textContent = content || '';
374
+ }
375
+ });
376
+ this.pendingTextUpdates.clear();
377
+ }
378
+
379
+ // --- Initialization ---
380
+ init(containerId, helper) {
381
+ // Re-activation logic
382
+ if (this.container) {
383
+ const target = document.getElementById(containerId);
384
+ if (target && this.renderer && this.cssRenderer) {
385
+ // Remove canvases from previous parent
386
+ try {
387
+ if (this.renderer.domElement.parentElement) {
388
+ this.renderer.domElement.parentElement.removeChild(this.renderer.domElement);
389
+ }
390
+ if (this.cssRenderer.domElement.parentElement) {
391
+ this.cssRenderer.domElement.parentElement.removeChild(this.cssRenderer.domElement);
392
+ }
393
+ } catch { }
394
+
395
+ // Attach canvases to the new container
396
+ target.appendChild(this.renderer.domElement);
397
+ target.appendChild(this.cssRenderer.domElement);
398
+
399
+ // Update references
400
+ this.container = target;
401
+ this.dotNetHelper = helper;
402
+ target.style.display = 'block';
403
+ // Trigger resize handler
404
+ this.onResize();
405
+ // Restart animation loop if it was stopped
406
+ if (!this.animationFrameId) {
407
+ this.animate();
408
+ }
409
+ if (pendingSettings) {
410
+ this.applySettings(pendingSettings);
411
+ } else {
412
+ this.applySettings({});
413
+ }
414
+ console.log(`[plan-master.js] Re-activated and animation loop resumed for container #${containerId}.`);
415
+ return;
416
+ }
417
+ }
418
+
419
+ // First-time init
420
+ if (!this.ensureThree() || !window.MindMapThemes) {
421
+ console.error('[plan-master.js] init failed: THREE, CSS3DRenderer, or MindMapThemes not loaded.');
422
+ return;
423
+ }
424
+
425
+ this.dotNetHelper = helper;
426
+ this.container = document.getElementById(containerId);
427
+ if (!this.container) {
428
+ console.error('[plan-master.js] Container not found!');
429
+ return;
430
+ }
431
+
432
+ this.container.style.display = 'block';
433
+
434
+ const THREE = globalThis.THREE;
435
+ this.scene = new THREE.Scene();
436
+
437
+ // Camera setup
438
+ const NEAR = 0.1;
439
+ const FAR = 1e7;
440
+ this.camera = new THREE.PerspectiveCamera(50, this.container.clientWidth / this.container.clientHeight, NEAR, FAR);
441
+ const initialZ = 1200;
442
+ this.camera.position.z = initialZ;
443
+ this.targetZ = initialZ;
444
+ this.targetX = this.camera.position.x;
445
+ this.targetY = this.camera.position.y;
446
+
447
+ // WebGL renderer setup
448
+ this.renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
449
+ this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
450
+ this.renderer.setPixelRatio(window.devicePixelRatio || 1);
451
+ this.renderer.domElement.style.position = 'absolute';
452
+ this.renderer.domElement.style.top = 0;
453
+ this.renderer.domElement.style.left = 0;
454
+ this.renderer.domElement.style.zIndex = 0;
455
+ this.container.appendChild(this.renderer.domElement);
456
+
457
+ // CSS3D renderer setup
458
+ const CSS3DRendererCtor = globalThis.CSS3DRenderer;
459
+ this.cssRenderer = new CSS3DRendererCtor();
460
+ this.cssRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
461
+ this.cssRenderer.domElement.style.position = 'absolute';
462
+ this.cssRenderer.domElement.style.top = 0;
463
+ this.cssRenderer.domElement.style.left = 0;
464
+ this.cssRenderer.domElement.style.zIndex = 1;
465
+ this.container.appendChild(this.cssRenderer.domElement);
466
+
467
+ // Background theme (sync with MindCanvas GeneralSettings)
468
+ if (pendingSettings) {
469
+ this.applySettings(pendingSettings);
470
+ } else {
471
+ this.applySettings({});
472
+ }
473
+
474
+ // Register event listeners
475
+ this.cssRenderer.domElement.addEventListener('mousedown', this.boundOnMouseDown);
476
+ this.cssRenderer.domElement.addEventListener('click', this.boundOnContainerClick);
477
+ this.cssRenderer.domElement.addEventListener('wheel', this.boundOnWheel, { passive: false });
478
+ this.cssRenderer.domElement.addEventListener('contextmenu', this.boundOnContextMenu);
479
+ window.addEventListener('resize', this.boundOnResize);
480
+ window.addEventListener('keydown', this.boundOnKeyDown);
481
+
482
+ // Start animation
483
+ this.animate();
484
+
485
+ console.log(`[plan-master.js] Initialized for container #${containerId}.`);
486
+ }
487
+
488
+ // --- Background theme ---
489
+ setBackgroundTheme(themeName) {
490
+ if (themeName === this.currentThemeName || !this.scene || !window.MindMapThemes) return;
491
+ const newTheme = window.MindMapThemes.getTheme(themeName);
492
+ if (!newTheme) {
493
+ console.warn(`[plan-master.js] Background theme '${themeName}' not found.`);
494
+ return;
495
+ }
496
+
497
+ // Dispose previous theme
498
+ if (this.currentThemeObject) {
499
+ const oldTheme = window.MindMapThemes.getTheme(this.currentThemeName);
500
+ try { oldTheme?.dispose(this.currentThemeObject); } catch { }
501
+ if (this.scene) this.scene.remove(this.currentThemeObject);
502
+ }
503
+
504
+ // Create and attach new theme
505
+ this.currentThemeObject = newTheme.create(this.scene, this.renderer);
506
+ if (this.currentThemeObject) this.scene.add(this.currentThemeObject);
507
+ this.currentThemeName = themeName;
508
+ console.log(`[plan-master.js] Background theme set to: ${themeName}`);
509
+ }
510
+
511
+ // --- Add node ---
512
+ addNode(nodeModel) {
513
+ if (this.nodeObjectsById.has(nodeModel.id)) {
514
+ return;
515
+ }
516
+
517
+ console.log(`[plan-master.js] addNode called for ID: ${nodeModel.id}`);
518
+ const el = document.getElementById(`node-${nodeModel.id}`);
519
+ if (!el) {
520
+ console.warn(`[plan-master.js] Element 'node-${nodeModel.id}' not found in DOM.`);
521
+ return;
522
+ }
523
+
524
+ const nodeContent = el.firstElementChild || el;
525
+ const nodeClone = nodeContent.cloneNode(true);
526
+ nodeClone.dataset.nodeId = nodeModel.id;
527
+ nodeClone.style.cursor = 'pointer';
528
+ nodeClone.style.transformOrigin = '0% 0%';
529
+
530
+ // [Fix] Ensure the DOM element size matches the logical node size
531
+ // This prevents mismatch between the visual area and the draggable area
532
+ if (nodeModel.width && nodeModel.width > 0) {
533
+ nodeClone.style.width = nodeModel.width + 'px';
534
+ }
535
+ // For text/markdown nodes, height is dynamic based on content.
536
+ // For fixed-height types (note, pdf, image), enforce the height.
537
+ if (nodeModel.contentType === 'text') {
538
+ nodeClone.style.height = 'auto';
539
+ } else if (nodeModel.height && nodeModel.height > 0) {
540
+ nodeClone.style.height = nodeModel.height + 'px';
541
+ }
542
+
543
+ const contentTarget = nodeClone.querySelector(`#node-response-${nodeModel.id}`);
544
+ if (contentTarget) {
545
+ this.nodeContentTargets[nodeModel.id] = contentTarget;
546
+ } else {
547
+ console.error(`[plan-master.js] Could not find content target for node ${nodeModel.id}.`);
548
+ }
549
+
550
+ const loadingTarget = nodeClone.querySelector(`#node-loading-${nodeModel.id}`);
551
+ const bubbleTarget = nodeClone.querySelector('.map-node-bubble');
552
+ this.nodeElements[nodeModel.id] = {
553
+ content: contentTarget || null,
554
+ loading: loadingTarget || null,
555
+ bubble: bubbleTarget || nodeClone
556
+ };
557
+
558
+ let clickStartTime = 0;
559
+ nodeClone.addEventListener('mousedown', (e) => {
560
+ if (e.button === 0) {
561
+ e.stopPropagation();
562
+ this.isDraggingNode = true;
563
+ this.draggedNodeObject = obj;
564
+ this.lastMousePos = { x: e.clientX, y: e.clientY };
565
+ clickStartTime = Date.now();
566
+ window.addEventListener('mousemove', this.boundOnMouseMove);
567
+ window.addEventListener('mouseup', this.boundOnMouseUp);
568
+ }
569
+ });
570
+
571
+ nodeClone.addEventListener('click', (e) => {
572
+ e.stopPropagation();
573
+ if (Date.now() - clickStartTime < 200) {
574
+ const nid = e.currentTarget.dataset.nodeId;
575
+ if (nid && this.dotNetHelper) {
576
+ this.dotNetHelper.invokeMethodAsync('SelectNodeInBlazor', nid);
577
+ }
578
+ }
579
+ });
580
+
581
+ const CSS3DObjectCtor = globalThis.CSS3DObject || (globalThis.THREE && globalThis.THREE.CSS3DObject);
582
+ const obj = new CSS3DObjectCtor(nodeClone);
583
+ obj.position.set(nodeModel.positionX || 0, nodeModel.positionY || 0, 1);
584
+ this.scene.add(obj);
585
+ this.nodeObjectsById.set(nodeModel.id, obj);
586
+ console.log(`[plan-master.js] Node ${nodeModel.id} added to Three.js scene.`);
587
+ }
588
+
589
+ // --- Remove node ---
590
+ removeNode(nodeId) {
591
+ const obj = this.nodeObjectsById.get(nodeId);
592
+ if (obj) {
593
+ if (this.scene) this.scene.remove(obj);
594
+ this.nodeObjectsById.delete(nodeId);
595
+ delete this.nodeElements[nodeId];
596
+ delete this.nodeContentTargets[nodeId];
597
+ this.latestMarkdownById.delete(nodeId);
598
+ this.throttledParseFlags.delete(nodeId);
599
+ this.pendingTextUpdates.delete(nodeId);
600
+ console.log(`[plan-master.js] Node ${nodeId} removed from scene.`);
601
+ }
602
+ }
603
+
604
+ // --- Update node content ---
605
+ updateNodeContent(nodeId, markdownContent) {
606
+ const id = String(nodeId);
607
+ this.latestMarkdownById.set(id, markdownContent || '');
608
+ this.pendingTextUpdates.set(id, markdownContent || '');
609
+ if (!this.isTextUpdateScheduled) {
610
+ this.isTextUpdateScheduled = true;
611
+ requestAnimationFrame(() => {
612
+ this.processPendingTextUpdates();
613
+ this.isTextUpdateScheduled = false;
614
+ });
615
+ }
616
+ }
617
+
618
+ // --- Update node selection ---
619
+ updateNodeSelection(oldNodeId, newNodeId) {
620
+ if (oldNodeId) {
621
+ const oldElements = this.nodeElements[oldNodeId];
622
+ if (oldElements && oldElements.bubble) {
623
+ oldElements.bubble.classList.remove('selected');
624
+ }
625
+ }
626
+ if (newNodeId) {
627
+ const newElements = this.nodeElements[newNodeId];
628
+ if (newElements && newElements.bubble) {
629
+ newElements.bubble.classList.add('selected');
630
+ }
631
+ }
632
+ }
633
+
634
+ // --- Hide (tab switch) ---
635
+ hide() {
636
+ if (this.container) {
637
+ this.container.style.display = 'none';
638
+ // Stop animation loop
639
+ if (this.animationFrameId) {
640
+ cancelAnimationFrame(this.animationFrameId);
641
+ this.animationFrameId = null;
642
+ }
643
+ console.log('[plan-master.js] Hidden and animation loop paused.');
644
+ }
645
+ }
646
+
647
+ // --- Cleanup and dispose ---
648
+ cleanupAndDispose() {
649
+ if (!this.container) return;
650
+
651
+ // Stop animation loop
652
+ if (this.animationFrameId) {
653
+ cancelAnimationFrame(this.animationFrameId);
654
+ this.animationFrameId = null;
655
+ }
656
+
657
+ // Remove event listeners
658
+ if (this.cssRenderer && this.cssRenderer.domElement) {
659
+ this.cssRenderer.domElement.removeEventListener('mousedown', this.boundOnMouseDown);
660
+ this.cssRenderer.domElement.removeEventListener('click', this.boundOnContainerClick);
661
+ this.cssRenderer.domElement.removeEventListener('wheel', this.boundOnWheel);
662
+ this.cssRenderer.domElement.removeEventListener('contextmenu', this.boundOnContextMenu);
663
+ }
664
+ window.removeEventListener('mousemove', this.boundOnMouseMove);
665
+ window.removeEventListener('mouseup', this.boundOnMouseUp);
666
+ window.removeEventListener('resize', this.boundOnResize);
667
+ window.removeEventListener('keydown', this.boundOnKeyDown);
668
+
669
+ // Theme cleanup
670
+ if (this.currentThemeObject && window.MindMapThemes) {
671
+ const theme = window.MindMapThemes.getTheme(this.currentThemeName);
672
+ try { theme?.dispose(this.currentThemeObject); } catch { }
673
+ if (this.scene) this.scene.remove(this.currentThemeObject);
674
+ }
675
+ this.currentThemeObject = null;
676
+ this.currentThemeName = null;
677
+
678
+ // Reset state
679
+ try { this.pendingTextUpdates.clear(); } catch { }
680
+ try { this.throttledParseFlags.clear(); } catch { }
681
+ try { this.latestMarkdownById.clear(); } catch { }
682
+ this.nodeContentTargets = {};
683
+ this.nodeElements = {};
684
+ try { this.nodeObjectsById.clear(); } catch { }
685
+
686
+ // Dispose scene/renderer resources
687
+ if (this.scene) {
688
+ this.scene.traverse(object => {
689
+ if (object.geometry) object.geometry.dispose();
690
+ if (object.material) {
691
+ if (Array.isArray(object.material)) {
692
+ object.material.forEach(material => material.dispose());
693
+ } else {
694
+ object.material.dispose();
695
+ }
696
+ }
697
+ });
698
+ }
699
+ if (this.renderer) this.renderer.dispose();
700
+ if (this.cssRenderer && this.cssRenderer.domElement && this.cssRenderer.domElement.parentElement) {
701
+ this.cssRenderer.domElement.parentElement.removeChild(this.cssRenderer.domElement);
702
+ }
703
+
704
+ // Clear references
705
+ this.scene = null;
706
+ this.camera = null;
707
+ this.renderer = null;
708
+ this.cssRenderer = null;
709
+ this.container = null;
710
+ this.dotNetHelper = null;
711
+
712
+ console.log('[plan-master.js] Disposed all resources.');
713
+ }
714
+ }
715
+
716
+ // --- Public window.planMaster interface ---
717
+ window.planMaster = {
718
+ init: function (containerId, helper) {
719
+ if (!moduleInstance) {
720
+ moduleInstance = new PlanMasterModule();
721
+ }
722
+ moduleInstance.init(containerId, helper);
723
+ },
724
+ addNode: function (nodeModel) {
725
+ if (moduleInstance) moduleInstance.addNode(nodeModel);
726
+ },
727
+ removeNode: function (nodeId) {
728
+ if (moduleInstance) moduleInstance.removeNode(nodeId);
729
+ },
730
+ updateNodeContent: function (nodeId, markdownContent) {
731
+ if (moduleInstance) moduleInstance.updateNodeContent(nodeId, markdownContent);
732
+ },
733
+ updateNodeSelection: function (oldNodeId, newNodeId) {
734
+ if (moduleInstance) moduleInstance.updateNodeSelection(oldNodeId, newNodeId);
735
+ },
736
+ applySettings: function (settings) {
737
+ pendingSettings = Object.assign({}, pendingSettings || {}, settings || {});
738
+ if (moduleInstance) {
739
+ moduleInstance.applySettings(pendingSettings);
740
+ }
741
+ },
742
+ setBackgroundTheme: function (themeName) {
743
+ if (moduleInstance) moduleInstance.setBackgroundTheme(themeName);
744
+ },
745
+ hide: function () {
746
+ if (moduleInstance) moduleInstance.hide();
747
+ },
748
+ clearAllNodes: function () {
749
+ if (moduleInstance && moduleInstance.nodeObjectsById) {
750
+ // Remove all nodes from scene
751
+ moduleInstance.nodeObjectsById.forEach((obj, nodeId) => {
752
+ if (moduleInstance.scene) {
753
+ moduleInstance.scene.remove(obj);
754
+ }
755
+ // Cleanup textures if any
756
+ if (obj.material) {
757
+ if (obj.material.map) obj.material.map.dispose();
758
+ obj.material.dispose();
759
+ }
760
+ if (obj.geometry) obj.geometry.dispose();
761
+ });
762
+ moduleInstance.nodeObjectsById.clear();
763
+
764
+ // Clear related caches
765
+ if (moduleInstance.nodeElements) moduleInstance.nodeElements = {};
766
+ if (moduleInstance.nodeContentTargets) moduleInstance.nodeContentTargets = {};
767
+ if (moduleInstance.latestMarkdownById) moduleInstance.latestMarkdownById.clear();
768
+ if (moduleInstance.throttledParseFlags) moduleInstance.throttledParseFlags.clear();
769
+ if (moduleInstance.pendingTextUpdates) moduleInstance.pendingTextUpdates.clear();
770
+
771
+ console.log('[planAgent] All nodes cleared');
772
+ }
773
+ },
774
+ cleanupAndDispose: function () {
775
+ if (moduleInstance) {
776
+ moduleInstance.cleanupAndDispose();
777
+ moduleInstance = null;
778
+ }
779
+ pendingSettings = null;
780
+ }
781
+ };
782
+
783
+ // Backward-compatible alias: PlanAgent is the new page/internal name.
784
+ window.planAgent = window.planMaster;
785
+
786
+ console.log('? plan-master.js loaded and ready (Copied from code-master.js).');
787
+ })();
788
+