helixmind 0.5.4

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 (808) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +323 -0
  3. package/dist/cli/agent/autonomous.d.ts +24 -0
  4. package/dist/cli/agent/autonomous.d.ts.map +1 -0
  5. package/dist/cli/agent/autonomous.js +194 -0
  6. package/dist/cli/agent/autonomous.js.map +1 -0
  7. package/dist/cli/agent/loop.d.ts +87 -0
  8. package/dist/cli/agent/loop.d.ts.map +1 -0
  9. package/dist/cli/agent/loop.js +492 -0
  10. package/dist/cli/agent/loop.js.map +1 -0
  11. package/dist/cli/agent/monitor/alerter.d.ts +29 -0
  12. package/dist/cli/agent/monitor/alerter.d.ts.map +1 -0
  13. package/dist/cli/agent/monitor/alerter.js +80 -0
  14. package/dist/cli/agent/monitor/alerter.js.map +1 -0
  15. package/dist/cli/agent/monitor/baseline.d.ts +14 -0
  16. package/dist/cli/agent/monitor/baseline.d.ts.map +1 -0
  17. package/dist/cli/agent/monitor/baseline.js +157 -0
  18. package/dist/cli/agent/monitor/baseline.js.map +1 -0
  19. package/dist/cli/agent/monitor/prompts.d.ts +9 -0
  20. package/dist/cli/agent/monitor/prompts.d.ts.map +1 -0
  21. package/dist/cli/agent/monitor/prompts.js +103 -0
  22. package/dist/cli/agent/monitor/prompts.js.map +1 -0
  23. package/dist/cli/agent/monitor/responder.d.ts +12 -0
  24. package/dist/cli/agent/monitor/responder.d.ts.map +1 -0
  25. package/dist/cli/agent/monitor/responder.js +59 -0
  26. package/dist/cli/agent/monitor/responder.js.map +1 -0
  27. package/dist/cli/agent/monitor/scanner.d.ts +18 -0
  28. package/dist/cli/agent/monitor/scanner.d.ts.map +1 -0
  29. package/dist/cli/agent/monitor/scanner.js +81 -0
  30. package/dist/cli/agent/monitor/scanner.js.map +1 -0
  31. package/dist/cli/agent/monitor/types.d.ts +119 -0
  32. package/dist/cli/agent/monitor/types.d.ts.map +1 -0
  33. package/dist/cli/agent/monitor/types.js +5 -0
  34. package/dist/cli/agent/monitor/types.js.map +1 -0
  35. package/dist/cli/agent/monitor/watcher.d.ts +4 -0
  36. package/dist/cli/agent/monitor/watcher.d.ts.map +1 -0
  37. package/dist/cli/agent/monitor/watcher.js +214 -0
  38. package/dist/cli/agent/monitor/watcher.js.map +1 -0
  39. package/dist/cli/agent/permissions.d.ts +65 -0
  40. package/dist/cli/agent/permissions.d.ts.map +1 -0
  41. package/dist/cli/agent/permissions.js +447 -0
  42. package/dist/cli/agent/permissions.js.map +1 -0
  43. package/dist/cli/agent/plan-engine.d.ts +72 -0
  44. package/dist/cli/agent/plan-engine.d.ts.map +1 -0
  45. package/dist/cli/agent/plan-engine.js +261 -0
  46. package/dist/cli/agent/plan-engine.js.map +1 -0
  47. package/dist/cli/agent/plan-executor.d.ts +37 -0
  48. package/dist/cli/agent/plan-executor.d.ts.map +1 -0
  49. package/dist/cli/agent/plan-executor.js +105 -0
  50. package/dist/cli/agent/plan-executor.js.map +1 -0
  51. package/dist/cli/agent/plan-types.d.ts +50 -0
  52. package/dist/cli/agent/plan-types.d.ts.map +1 -0
  53. package/dist/cli/agent/plan-types.js +58 -0
  54. package/dist/cli/agent/plan-types.js.map +1 -0
  55. package/dist/cli/agent/sandbox.d.ts +28 -0
  56. package/dist/cli/agent/sandbox.d.ts.map +1 -0
  57. package/dist/cli/agent/sandbox.js +298 -0
  58. package/dist/cli/agent/sandbox.js.map +1 -0
  59. package/dist/cli/agent/swarm.d.ts +75 -0
  60. package/dist/cli/agent/swarm.d.ts.map +1 -0
  61. package/dist/cli/agent/swarm.js +272 -0
  62. package/dist/cli/agent/swarm.js.map +1 -0
  63. package/dist/cli/agent/tools/browser-click.d.ts +2 -0
  64. package/dist/cli/agent/tools/browser-click.d.ts.map +1 -0
  65. package/dist/cli/agent/tools/browser-click.js +35 -0
  66. package/dist/cli/agent/tools/browser-click.js.map +1 -0
  67. package/dist/cli/agent/tools/browser-close.d.ts +2 -0
  68. package/dist/cli/agent/tools/browser-close.d.ts.map +1 -0
  69. package/dist/cli/agent/tools/browser-close.js +27 -0
  70. package/dist/cli/agent/tools/browser-close.js.map +1 -0
  71. package/dist/cli/agent/tools/browser-navigate.d.ts +2 -0
  72. package/dist/cli/agent/tools/browser-navigate.d.ts.map +1 -0
  73. package/dist/cli/agent/tools/browser-navigate.js +27 -0
  74. package/dist/cli/agent/tools/browser-navigate.js.map +1 -0
  75. package/dist/cli/agent/tools/browser-open.d.ts +2 -0
  76. package/dist/cli/agent/tools/browser-open.d.ts.map +1 -0
  77. package/dist/cli/agent/tools/browser-open.js +38 -0
  78. package/dist/cli/agent/tools/browser-open.js.map +1 -0
  79. package/dist/cli/agent/tools/browser-screenshot.d.ts +2 -0
  80. package/dist/cli/agent/tools/browser-screenshot.d.ts.map +1 -0
  81. package/dist/cli/agent/tools/browser-screenshot.js +68 -0
  82. package/dist/cli/agent/tools/browser-screenshot.js.map +1 -0
  83. package/dist/cli/agent/tools/browser-type.d.ts +2 -0
  84. package/dist/cli/agent/tools/browser-type.d.ts.map +1 -0
  85. package/dist/cli/agent/tools/browser-type.js +33 -0
  86. package/dist/cli/agent/tools/browser-type.js.map +1 -0
  87. package/dist/cli/agent/tools/bug-list.d.ts +2 -0
  88. package/dist/cli/agent/tools/bug-list.d.ts.map +1 -0
  89. package/dist/cli/agent/tools/bug-list.js +82 -0
  90. package/dist/cli/agent/tools/bug-list.js.map +1 -0
  91. package/dist/cli/agent/tools/bug-report.d.ts +2 -0
  92. package/dist/cli/agent/tools/bug-report.d.ts.map +1 -0
  93. package/dist/cli/agent/tools/bug-report.js +130 -0
  94. package/dist/cli/agent/tools/bug-report.js.map +1 -0
  95. package/dist/cli/agent/tools/edit-file.d.ts +2 -0
  96. package/dist/cli/agent/tools/edit-file.d.ts.map +1 -0
  97. package/dist/cli/agent/tools/edit-file.js +61 -0
  98. package/dist/cli/agent/tools/edit-file.js.map +1 -0
  99. package/dist/cli/agent/tools/find.d.ts +2 -0
  100. package/dist/cli/agent/tools/find.d.ts.map +1 -0
  101. package/dist/cli/agent/tools/find.js +35 -0
  102. package/dist/cli/agent/tools/find.js.map +1 -0
  103. package/dist/cli/agent/tools/git-commit.d.ts +2 -0
  104. package/dist/cli/agent/tools/git-commit.d.ts.map +1 -0
  105. package/dist/cli/agent/tools/git-commit.js +57 -0
  106. package/dist/cli/agent/tools/git-commit.js.map +1 -0
  107. package/dist/cli/agent/tools/git-diff.d.ts +2 -0
  108. package/dist/cli/agent/tools/git-diff.d.ts.map +1 -0
  109. package/dist/cli/agent/tools/git-diff.js +45 -0
  110. package/dist/cli/agent/tools/git-diff.js.map +1 -0
  111. package/dist/cli/agent/tools/git-log.d.ts +2 -0
  112. package/dist/cli/agent/tools/git-log.d.ts.map +1 -0
  113. package/dist/cli/agent/tools/git-log.js +41 -0
  114. package/dist/cli/agent/tools/git-log.js.map +1 -0
  115. package/dist/cli/agent/tools/git-status.d.ts +2 -0
  116. package/dist/cli/agent/tools/git-status.d.ts.map +1 -0
  117. package/dist/cli/agent/tools/git-status.js +52 -0
  118. package/dist/cli/agent/tools/git-status.js.map +1 -0
  119. package/dist/cli/agent/tools/list-dir.d.ts +2 -0
  120. package/dist/cli/agent/tools/list-dir.d.ts.map +1 -0
  121. package/dist/cli/agent/tools/list-dir.js +73 -0
  122. package/dist/cli/agent/tools/list-dir.js.map +1 -0
  123. package/dist/cli/agent/tools/read-file.d.ts +2 -0
  124. package/dist/cli/agent/tools/read-file.d.ts.map +1 -0
  125. package/dist/cli/agent/tools/read-file.js +45 -0
  126. package/dist/cli/agent/tools/read-file.js.map +1 -0
  127. package/dist/cli/agent/tools/registry.d.ts +34 -0
  128. package/dist/cli/agent/tools/registry.d.ts.map +1 -0
  129. package/dist/cli/agent/tools/registry.js +53 -0
  130. package/dist/cli/agent/tools/registry.js.map +1 -0
  131. package/dist/cli/agent/tools/run-command.d.ts +2 -0
  132. package/dist/cli/agent/tools/run-command.d.ts.map +1 -0
  133. package/dist/cli/agent/tools/run-command.js +112 -0
  134. package/dist/cli/agent/tools/run-command.js.map +1 -0
  135. package/dist/cli/agent/tools/search.d.ts +2 -0
  136. package/dist/cli/agent/tools/search.d.ts.map +1 -0
  137. package/dist/cli/agent/tools/search.js +104 -0
  138. package/dist/cli/agent/tools/search.js.map +1 -0
  139. package/dist/cli/agent/tools/spiral-query.d.ts +2 -0
  140. package/dist/cli/agent/tools/spiral-query.d.ts.map +1 -0
  141. package/dist/cli/agent/tools/spiral-query.js +52 -0
  142. package/dist/cli/agent/tools/spiral-query.js.map +1 -0
  143. package/dist/cli/agent/tools/spiral-store.d.ts +2 -0
  144. package/dist/cli/agent/tools/spiral-store.d.ts.map +1 -0
  145. package/dist/cli/agent/tools/spiral-store.js +37 -0
  146. package/dist/cli/agent/tools/spiral-store.js.map +1 -0
  147. package/dist/cli/agent/tools/web-research.d.ts +2 -0
  148. package/dist/cli/agent/tools/web-research.d.ts.map +1 -0
  149. package/dist/cli/agent/tools/web-research.js +96 -0
  150. package/dist/cli/agent/tools/web-research.js.map +1 -0
  151. package/dist/cli/agent/tools/write-file.d.ts +2 -0
  152. package/dist/cli/agent/tools/write-file.d.ts.map +1 -0
  153. package/dist/cli/agent/tools/write-file.js +86 -0
  154. package/dist/cli/agent/tools/write-file.js.map +1 -0
  155. package/dist/cli/agent/undo.d.ts +30 -0
  156. package/dist/cli/agent/undo.d.ts.map +1 -0
  157. package/dist/cli/agent/undo.js +48 -0
  158. package/dist/cli/agent/undo.js.map +1 -0
  159. package/dist/cli/auth/callback-server.d.ts +15 -0
  160. package/dist/cli/auth/callback-server.d.ts.map +1 -0
  161. package/dist/cli/auth/callback-server.js +169 -0
  162. package/dist/cli/auth/callback-server.js.map +1 -0
  163. package/dist/cli/auth/feature-gate.d.ts +47 -0
  164. package/dist/cli/auth/feature-gate.d.ts.map +1 -0
  165. package/dist/cli/auth/feature-gate.js +171 -0
  166. package/dist/cli/auth/feature-gate.js.map +1 -0
  167. package/dist/cli/auth/guard.d.ts +11 -0
  168. package/dist/cli/auth/guard.d.ts.map +1 -0
  169. package/dist/cli/auth/guard.js +94 -0
  170. package/dist/cli/auth/guard.js.map +1 -0
  171. package/dist/cli/auth/login.d.ts +22 -0
  172. package/dist/cli/auth/login.d.ts.map +1 -0
  173. package/dist/cli/auth/login.js +287 -0
  174. package/dist/cli/auth/login.js.map +1 -0
  175. package/dist/cli/auth/logout.d.ts +6 -0
  176. package/dist/cli/auth/logout.d.ts.map +1 -0
  177. package/dist/cli/auth/logout.js +36 -0
  178. package/dist/cli/auth/logout.js.map +1 -0
  179. package/dist/cli/bench/dataset.d.ts +13 -0
  180. package/dist/cli/bench/dataset.d.ts.map +1 -0
  181. package/dist/cli/bench/dataset.js +97 -0
  182. package/dist/cli/bench/dataset.js.map +1 -0
  183. package/dist/cli/bench/harness.d.ts +7 -0
  184. package/dist/cli/bench/harness.d.ts.map +1 -0
  185. package/dist/cli/bench/harness.js +135 -0
  186. package/dist/cli/bench/harness.js.map +1 -0
  187. package/dist/cli/bench/metrics.d.ts +15 -0
  188. package/dist/cli/bench/metrics.d.ts.map +1 -0
  189. package/dist/cli/bench/metrics.js +98 -0
  190. package/dist/cli/bench/metrics.js.map +1 -0
  191. package/dist/cli/bench/output.d.ts +42 -0
  192. package/dist/cli/bench/output.d.ts.map +1 -0
  193. package/dist/cli/bench/output.js +140 -0
  194. package/dist/cli/bench/output.js.map +1 -0
  195. package/dist/cli/bench/prompt.d.ts +13 -0
  196. package/dist/cli/bench/prompt.d.ts.map +1 -0
  197. package/dist/cli/bench/prompt.js +106 -0
  198. package/dist/cli/bench/prompt.js.map +1 -0
  199. package/dist/cli/bench/runner.d.ts +14 -0
  200. package/dist/cli/bench/runner.d.ts.map +1 -0
  201. package/dist/cli/bench/runner.js +334 -0
  202. package/dist/cli/bench/runner.js.map +1 -0
  203. package/dist/cli/bench/types.d.ts +109 -0
  204. package/dist/cli/bench/types.d.ts.map +1 -0
  205. package/dist/cli/bench/types.js +2 -0
  206. package/dist/cli/bench/types.js.map +1 -0
  207. package/dist/cli/bench/ui.d.ts +12 -0
  208. package/dist/cli/bench/ui.d.ts.map +1 -0
  209. package/dist/cli/bench/ui.js +126 -0
  210. package/dist/cli/bench/ui.js.map +1 -0
  211. package/dist/cli/brain/archive.d.ts +33 -0
  212. package/dist/cli/brain/archive.d.ts.map +1 -0
  213. package/dist/cli/brain/archive.js +166 -0
  214. package/dist/cli/brain/archive.js.map +1 -0
  215. package/dist/cli/brain/control-protocol.d.ts +913 -0
  216. package/dist/cli/brain/control-protocol.d.ts.map +1 -0
  217. package/dist/cli/brain/control-protocol.js +87 -0
  218. package/dist/cli/brain/control-protocol.js.map +1 -0
  219. package/dist/cli/brain/exporter.d.ts +34 -0
  220. package/dist/cli/brain/exporter.d.ts.map +1 -0
  221. package/dist/cli/brain/exporter.js +37 -0
  222. package/dist/cli/brain/exporter.js.map +1 -0
  223. package/dist/cli/brain/generator.d.ts +157 -0
  224. package/dist/cli/brain/generator.d.ts.map +1 -0
  225. package/dist/cli/brain/generator.js +633 -0
  226. package/dist/cli/brain/generator.js.map +1 -0
  227. package/dist/cli/brain/instance-manager.d.ts +42 -0
  228. package/dist/cli/brain/instance-manager.d.ts.map +1 -0
  229. package/dist/cli/brain/instance-manager.js +152 -0
  230. package/dist/cli/brain/instance-manager.js.map +1 -0
  231. package/dist/cli/brain/relay-client.d.ts +8 -0
  232. package/dist/cli/brain/relay-client.d.ts.map +1 -0
  233. package/dist/cli/brain/relay-client.js +505 -0
  234. package/dist/cli/brain/relay-client.js.map +1 -0
  235. package/dist/cli/brain/server.d.ts +40 -0
  236. package/dist/cli/brain/server.d.ts.map +1 -0
  237. package/dist/cli/brain/server.js +873 -0
  238. package/dist/cli/brain/server.js.map +1 -0
  239. package/dist/cli/brain/stdout-capture.d.ts +19 -0
  240. package/dist/cli/brain/stdout-capture.d.ts.map +1 -0
  241. package/dist/cli/brain/stdout-capture.js +45 -0
  242. package/dist/cli/brain/stdout-capture.js.map +1 -0
  243. package/dist/cli/brain/sync.d.ts +53 -0
  244. package/dist/cli/brain/sync.d.ts.map +1 -0
  245. package/dist/cli/brain/sync.js +113 -0
  246. package/dist/cli/brain/sync.js.map +1 -0
  247. package/dist/cli/brain/template.d.ts +3 -0
  248. package/dist/cli/brain/template.d.ts.map +1 -0
  249. package/dist/cli/brain/template.js +2099 -0
  250. package/dist/cli/brain/template.js.map +1 -0
  251. package/dist/cli/brain/web-chat-handler.d.ts +26 -0
  252. package/dist/cli/brain/web-chat-handler.d.ts.map +1 -0
  253. package/dist/cli/brain/web-chat-handler.js +134 -0
  254. package/dist/cli/brain/web-chat-handler.js.map +1 -0
  255. package/dist/cli/browser/chrome-finder.d.ts +12 -0
  256. package/dist/cli/browser/chrome-finder.d.ts.map +1 -0
  257. package/dist/cli/browser/chrome-finder.js +74 -0
  258. package/dist/cli/browser/chrome-finder.js.map +1 -0
  259. package/dist/cli/browser/controller.d.ts +51 -0
  260. package/dist/cli/browser/controller.d.ts.map +1 -0
  261. package/dist/cli/browser/controller.js +152 -0
  262. package/dist/cli/browser/controller.js.map +1 -0
  263. package/dist/cli/browser/vision.d.ts +38 -0
  264. package/dist/cli/browser/vision.d.ts.map +1 -0
  265. package/dist/cli/browser/vision.js +123 -0
  266. package/dist/cli/browser/vision.js.map +1 -0
  267. package/dist/cli/bugs/detector.d.ts +14 -0
  268. package/dist/cli/bugs/detector.d.ts.map +1 -0
  269. package/dist/cli/bugs/detector.js +108 -0
  270. package/dist/cli/bugs/detector.js.map +1 -0
  271. package/dist/cli/bugs/journal.d.ts +39 -0
  272. package/dist/cli/bugs/journal.d.ts.map +1 -0
  273. package/dist/cli/bugs/journal.js +195 -0
  274. package/dist/cli/bugs/journal.js.map +1 -0
  275. package/dist/cli/bugs/types.d.ts +27 -0
  276. package/dist/cli/bugs/types.d.ts.map +1 -0
  277. package/dist/cli/bugs/types.js +2 -0
  278. package/dist/cli/bugs/types.js.map +1 -0
  279. package/dist/cli/checkpoints/browser.d.ts +26 -0
  280. package/dist/cli/checkpoints/browser.d.ts.map +1 -0
  281. package/dist/cli/checkpoints/browser.js +272 -0
  282. package/dist/cli/checkpoints/browser.js.map +1 -0
  283. package/dist/cli/checkpoints/keybinding.d.ts +22 -0
  284. package/dist/cli/checkpoints/keybinding.d.ts.map +1 -0
  285. package/dist/cli/checkpoints/keybinding.js +44 -0
  286. package/dist/cli/checkpoints/keybinding.js.map +1 -0
  287. package/dist/cli/checkpoints/revert.d.ts +37 -0
  288. package/dist/cli/checkpoints/revert.d.ts.map +1 -0
  289. package/dist/cli/checkpoints/revert.js +144 -0
  290. package/dist/cli/checkpoints/revert.js.map +1 -0
  291. package/dist/cli/checkpoints/store.d.ts +48 -0
  292. package/dist/cli/checkpoints/store.d.ts.map +1 -0
  293. package/dist/cli/checkpoints/store.js +196 -0
  294. package/dist/cli/checkpoints/store.js.map +1 -0
  295. package/dist/cli/commands/archive.d.ts +7 -0
  296. package/dist/cli/commands/archive.d.ts.map +1 -0
  297. package/dist/cli/commands/archive.js +66 -0
  298. package/dist/cli/commands/archive.js.map +1 -0
  299. package/dist/cli/commands/auth.d.ts +10 -0
  300. package/dist/cli/commands/auth.d.ts.map +1 -0
  301. package/dist/cli/commands/auth.js +44 -0
  302. package/dist/cli/commands/auth.js.map +1 -0
  303. package/dist/cli/commands/bench.d.ts +25 -0
  304. package/dist/cli/commands/bench.d.ts.map +1 -0
  305. package/dist/cli/commands/bench.js +114 -0
  306. package/dist/cli/commands/bench.js.map +1 -0
  307. package/dist/cli/commands/chat.d.ts +11 -0
  308. package/dist/cli/commands/chat.d.ts.map +1 -0
  309. package/dist/cli/commands/chat.js +5363 -0
  310. package/dist/cli/commands/chat.js.map +1 -0
  311. package/dist/cli/commands/config.d.ts +4 -0
  312. package/dist/cli/commands/config.d.ts.map +1 -0
  313. package/dist/cli/commands/config.js +43 -0
  314. package/dist/cli/commands/config.js.map +1 -0
  315. package/dist/cli/commands/feed.d.ts +6 -0
  316. package/dist/cli/commands/feed.d.ts.map +1 -0
  317. package/dist/cli/commands/feed.js +95 -0
  318. package/dist/cli/commands/feed.js.map +1 -0
  319. package/dist/cli/commands/helix-menu.d.ts +4 -0
  320. package/dist/cli/commands/helix-menu.d.ts.map +1 -0
  321. package/dist/cli/commands/helix-menu.js +400 -0
  322. package/dist/cli/commands/helix-menu.js.map +1 -0
  323. package/dist/cli/commands/init.d.ts +2 -0
  324. package/dist/cli/commands/init.d.ts.map +1 -0
  325. package/dist/cli/commands/init.js +38 -0
  326. package/dist/cli/commands/init.js.map +1 -0
  327. package/dist/cli/commands/setup.d.ts +20 -0
  328. package/dist/cli/commands/setup.d.ts.map +1 -0
  329. package/dist/cli/commands/setup.js +310 -0
  330. package/dist/cli/commands/setup.js.map +1 -0
  331. package/dist/cli/commands/spiral.d.ts +4 -0
  332. package/dist/cli/commands/spiral.d.ts.map +1 -0
  333. package/dist/cli/commands/spiral.js +81 -0
  334. package/dist/cli/commands/spiral.js.map +1 -0
  335. package/dist/cli/config/store.d.ts +80 -0
  336. package/dist/cli/config/store.d.ts.map +1 -0
  337. package/dist/cli/config/store.js +247 -0
  338. package/dist/cli/config/store.js.map +1 -0
  339. package/dist/cli/config/trust.d.ts +21 -0
  340. package/dist/cli/config/trust.d.ts.map +1 -0
  341. package/dist/cli/config/trust.js +106 -0
  342. package/dist/cli/config/trust.js.map +1 -0
  343. package/dist/cli/context/assembler.d.ts +9 -0
  344. package/dist/cli/context/assembler.d.ts.map +1 -0
  345. package/dist/cli/context/assembler.js +217 -0
  346. package/dist/cli/context/assembler.js.map +1 -0
  347. package/dist/cli/context/project.d.ts +13 -0
  348. package/dist/cli/context/project.d.ts.map +1 -0
  349. package/dist/cli/context/project.js +126 -0
  350. package/dist/cli/context/project.js.map +1 -0
  351. package/dist/cli/context/session-buffer.d.ts +69 -0
  352. package/dist/cli/context/session-buffer.d.ts.map +1 -0
  353. package/dist/cli/context/session-buffer.js +362 -0
  354. package/dist/cli/context/session-buffer.js.map +1 -0
  355. package/dist/cli/context/trimmer.d.ts +26 -0
  356. package/dist/cli/context/trimmer.d.ts.map +1 -0
  357. package/dist/cli/context/trimmer.js +137 -0
  358. package/dist/cli/context/trimmer.js.map +1 -0
  359. package/dist/cli/core/index.d.ts +15 -0
  360. package/dist/cli/core/index.d.ts.map +1 -0
  361. package/dist/cli/core/index.js +12 -0
  362. package/dist/cli/core/index.js.map +1 -0
  363. package/dist/cli/core/input.d.ts +208 -0
  364. package/dist/cli/core/input.d.ts.map +1 -0
  365. package/dist/cli/core/input.js +807 -0
  366. package/dist/cli/core/input.js.map +1 -0
  367. package/dist/cli/core/screen.d.ts +211 -0
  368. package/dist/cli/core/screen.d.ts.map +1 -0
  369. package/dist/cli/core/screen.js +826 -0
  370. package/dist/cli/core/screen.js.map +1 -0
  371. package/dist/cli/core/terminal.d.ts +88 -0
  372. package/dist/cli/core/terminal.d.ts.map +1 -0
  373. package/dist/cli/core/terminal.js +200 -0
  374. package/dist/cli/core/terminal.js.map +1 -0
  375. package/dist/cli/feed/analyzer.d.ts +17 -0
  376. package/dist/cli/feed/analyzer.d.ts.map +1 -0
  377. package/dist/cli/feed/analyzer.js +220 -0
  378. package/dist/cli/feed/analyzer.js.map +1 -0
  379. package/dist/cli/feed/intent.d.ts +8 -0
  380. package/dist/cli/feed/intent.d.ts.map +1 -0
  381. package/dist/cli/feed/intent.js +70 -0
  382. package/dist/cli/feed/intent.js.map +1 -0
  383. package/dist/cli/feed/parser.d.ts +23 -0
  384. package/dist/cli/feed/parser.d.ts.map +1 -0
  385. package/dist/cli/feed/parser.js +166 -0
  386. package/dist/cli/feed/parser.js.map +1 -0
  387. package/dist/cli/feed/pipeline.d.ts +33 -0
  388. package/dist/cli/feed/pipeline.d.ts.map +1 -0
  389. package/dist/cli/feed/pipeline.js +250 -0
  390. package/dist/cli/feed/pipeline.js.map +1 -0
  391. package/dist/cli/feed/reader.d.ts +10 -0
  392. package/dist/cli/feed/reader.d.ts.map +1 -0
  393. package/dist/cli/feed/reader.js +61 -0
  394. package/dist/cli/feed/reader.js.map +1 -0
  395. package/dist/cli/feed/scanner.d.ts +10 -0
  396. package/dist/cli/feed/scanner.d.ts.map +1 -0
  397. package/dist/cli/feed/scanner.js +124 -0
  398. package/dist/cli/feed/scanner.js.map +1 -0
  399. package/dist/cli/feed/watcher.d.ts +14 -0
  400. package/dist/cli/feed/watcher.d.ts.map +1 -0
  401. package/dist/cli/feed/watcher.js +76 -0
  402. package/dist/cli/feed/watcher.js.map +1 -0
  403. package/dist/cli/helixmind.cmd +2 -0
  404. package/dist/cli/index.d.ts +3 -0
  405. package/dist/cli/index.d.ts.map +1 -0
  406. package/dist/cli/index.js +297 -0
  407. package/dist/cli/index.js.map +1 -0
  408. package/dist/cli/jarvis/autonomy.d.ts +55 -0
  409. package/dist/cli/jarvis/autonomy.d.ts.map +1 -0
  410. package/dist/cli/jarvis/autonomy.js +176 -0
  411. package/dist/cli/jarvis/autonomy.js.map +1 -0
  412. package/dist/cli/jarvis/code-reviewer.d.ts +35 -0
  413. package/dist/cli/jarvis/code-reviewer.d.ts.map +1 -0
  414. package/dist/cli/jarvis/code-reviewer.js +93 -0
  415. package/dist/cli/jarvis/code-reviewer.js.map +1 -0
  416. package/dist/cli/jarvis/core-ethics.d.ts +35 -0
  417. package/dist/cli/jarvis/core-ethics.d.ts.map +1 -0
  418. package/dist/cli/jarvis/core-ethics.js +246 -0
  419. package/dist/cli/jarvis/core-ethics.js.map +1 -0
  420. package/dist/cli/jarvis/daemon.d.ts +24 -0
  421. package/dist/cli/jarvis/daemon.d.ts.map +1 -0
  422. package/dist/cli/jarvis/daemon.js +230 -0
  423. package/dist/cli/jarvis/daemon.js.map +1 -0
  424. package/dist/cli/jarvis/dependency-guardian.d.ts +40 -0
  425. package/dist/cli/jarvis/dependency-guardian.d.ts.map +1 -0
  426. package/dist/cli/jarvis/dependency-guardian.js +148 -0
  427. package/dist/cli/jarvis/dependency-guardian.js.map +1 -0
  428. package/dist/cli/jarvis/git-intelligence.d.ts +36 -0
  429. package/dist/cli/jarvis/git-intelligence.d.ts.map +1 -0
  430. package/dist/cli/jarvis/git-intelligence.js +222 -0
  431. package/dist/cli/jarvis/git-intelligence.js.map +1 -0
  432. package/dist/cli/jarvis/identity.d.ts +57 -0
  433. package/dist/cli/jarvis/identity.d.ts.map +1 -0
  434. package/dist/cli/jarvis/identity.js +416 -0
  435. package/dist/cli/jarvis/identity.js.map +1 -0
  436. package/dist/cli/jarvis/index.d.ts +9 -0
  437. package/dist/cli/jarvis/index.d.ts.map +1 -0
  438. package/dist/cli/jarvis/index.js +7 -0
  439. package/dist/cli/jarvis/index.js.map +1 -0
  440. package/dist/cli/jarvis/instance-lock.d.ts +15 -0
  441. package/dist/cli/jarvis/instance-lock.d.ts.map +1 -0
  442. package/dist/cli/jarvis/instance-lock.js +95 -0
  443. package/dist/cli/jarvis/instance-lock.js.map +1 -0
  444. package/dist/cli/jarvis/learning.d.ts +73 -0
  445. package/dist/cli/jarvis/learning.d.ts.map +1 -0
  446. package/dist/cli/jarvis/learning.js +284 -0
  447. package/dist/cli/jarvis/learning.js.map +1 -0
  448. package/dist/cli/jarvis/multi-project.d.ts +39 -0
  449. package/dist/cli/jarvis/multi-project.d.ts.map +1 -0
  450. package/dist/cli/jarvis/multi-project.js +152 -0
  451. package/dist/cli/jarvis/multi-project.js.map +1 -0
  452. package/dist/cli/jarvis/notifications.d.ts +39 -0
  453. package/dist/cli/jarvis/notifications.d.ts.map +1 -0
  454. package/dist/cli/jarvis/notifications.js +216 -0
  455. package/dist/cli/jarvis/notifications.js.map +1 -0
  456. package/dist/cli/jarvis/onboarding.d.ts +19 -0
  457. package/dist/cli/jarvis/onboarding.d.ts.map +1 -0
  458. package/dist/cli/jarvis/onboarding.js +116 -0
  459. package/dist/cli/jarvis/onboarding.js.map +1 -0
  460. package/dist/cli/jarvis/orchestrator.d.ts +46 -0
  461. package/dist/cli/jarvis/orchestrator.d.ts.map +1 -0
  462. package/dist/cli/jarvis/orchestrator.js +253 -0
  463. package/dist/cli/jarvis/orchestrator.js.map +1 -0
  464. package/dist/cli/jarvis/parallel.d.ts +63 -0
  465. package/dist/cli/jarvis/parallel.d.ts.map +1 -0
  466. package/dist/cli/jarvis/parallel.js +172 -0
  467. package/dist/cli/jarvis/parallel.js.map +1 -0
  468. package/dist/cli/jarvis/performance-profiler.d.ts +31 -0
  469. package/dist/cli/jarvis/performance-profiler.d.ts.map +1 -0
  470. package/dist/cli/jarvis/performance-profiler.js +229 -0
  471. package/dist/cli/jarvis/performance-profiler.js.map +1 -0
  472. package/dist/cli/jarvis/proposals.d.ts +80 -0
  473. package/dist/cli/jarvis/proposals.d.ts.map +1 -0
  474. package/dist/cli/jarvis/proposals.js +286 -0
  475. package/dist/cli/jarvis/proposals.js.map +1 -0
  476. package/dist/cli/jarvis/queue.d.ts +41 -0
  477. package/dist/cli/jarvis/queue.d.ts.map +1 -0
  478. package/dist/cli/jarvis/queue.js +245 -0
  479. package/dist/cli/jarvis/queue.js.map +1 -0
  480. package/dist/cli/jarvis/runtime-context.d.ts +34 -0
  481. package/dist/cli/jarvis/runtime-context.d.ts.map +1 -0
  482. package/dist/cli/jarvis/runtime-context.js +113 -0
  483. package/dist/cli/jarvis/runtime-context.js.map +1 -0
  484. package/dist/cli/jarvis/scheduler.d.ts +21 -0
  485. package/dist/cli/jarvis/scheduler.d.ts.map +1 -0
  486. package/dist/cli/jarvis/scheduler.js +182 -0
  487. package/dist/cli/jarvis/scheduler.js.map +1 -0
  488. package/dist/cli/jarvis/sentiment.d.ts +29 -0
  489. package/dist/cli/jarvis/sentiment.d.ts.map +1 -0
  490. package/dist/cli/jarvis/sentiment.js +221 -0
  491. package/dist/cli/jarvis/sentiment.js.map +1 -0
  492. package/dist/cli/jarvis/skill-scoring.d.ts +63 -0
  493. package/dist/cli/jarvis/skill-scoring.d.ts.map +1 -0
  494. package/dist/cli/jarvis/skill-scoring.js +226 -0
  495. package/dist/cli/jarvis/skill-scoring.js.map +1 -0
  496. package/dist/cli/jarvis/skills.d.ts +87 -0
  497. package/dist/cli/jarvis/skills.d.ts.map +1 -0
  498. package/dist/cli/jarvis/skills.js +367 -0
  499. package/dist/cli/jarvis/skills.js.map +1 -0
  500. package/dist/cli/jarvis/telegram-bot.d.ts +77 -0
  501. package/dist/cli/jarvis/telegram-bot.d.ts.map +1 -0
  502. package/dist/cli/jarvis/telegram-bot.js +251 -0
  503. package/dist/cli/jarvis/telegram-bot.js.map +1 -0
  504. package/dist/cli/jarvis/telemetry.d.ts +32 -0
  505. package/dist/cli/jarvis/telemetry.d.ts.map +1 -0
  506. package/dist/cli/jarvis/telemetry.js +213 -0
  507. package/dist/cli/jarvis/telemetry.js.map +1 -0
  508. package/dist/cli/jarvis/test-sentinel.d.ts +36 -0
  509. package/dist/cli/jarvis/test-sentinel.d.ts.map +1 -0
  510. package/dist/cli/jarvis/test-sentinel.js +178 -0
  511. package/dist/cli/jarvis/test-sentinel.js.map +1 -0
  512. package/dist/cli/jarvis/thinking-loop.d.ts +15 -0
  513. package/dist/cli/jarvis/thinking-loop.d.ts.map +1 -0
  514. package/dist/cli/jarvis/thinking-loop.js +437 -0
  515. package/dist/cli/jarvis/thinking-loop.js.map +1 -0
  516. package/dist/cli/jarvis/triggers.d.ts +23 -0
  517. package/dist/cli/jarvis/triggers.d.ts.map +1 -0
  518. package/dist/cli/jarvis/triggers.js +157 -0
  519. package/dist/cli/jarvis/triggers.js.map +1 -0
  520. package/dist/cli/jarvis/types.d.ts +582 -0
  521. package/dist/cli/jarvis/types.d.ts.map +1 -0
  522. package/dist/cli/jarvis/types.js +18 -0
  523. package/dist/cli/jarvis/types.js.map +1 -0
  524. package/dist/cli/jarvis/voice-bridge.d.ts +68 -0
  525. package/dist/cli/jarvis/voice-bridge.d.ts.map +1 -0
  526. package/dist/cli/jarvis/voice-bridge.js +254 -0
  527. package/dist/cli/jarvis/voice-bridge.js.map +1 -0
  528. package/dist/cli/jarvis/world-model.d.ts +43 -0
  529. package/dist/cli/jarvis/world-model.d.ts.map +1 -0
  530. package/dist/cli/jarvis/world-model.js +209 -0
  531. package/dist/cli/jarvis/world-model.js.map +1 -0
  532. package/dist/cli/jarvis-proxy/client.d.ts +18 -0
  533. package/dist/cli/jarvis-proxy/client.d.ts.map +1 -0
  534. package/dist/cli/jarvis-proxy/client.js +64 -0
  535. package/dist/cli/jarvis-proxy/client.js.map +1 -0
  536. package/dist/cli/jarvis-proxy/executor.d.ts +13 -0
  537. package/dist/cli/jarvis-proxy/executor.d.ts.map +1 -0
  538. package/dist/cli/jarvis-proxy/executor.js +32 -0
  539. package/dist/cli/jarvis-proxy/executor.js.map +1 -0
  540. package/dist/cli/jarvis-proxy/types.d.ts +25 -0
  541. package/dist/cli/jarvis-proxy/types.d.ts.map +1 -0
  542. package/dist/cli/jarvis-proxy/types.js +7 -0
  543. package/dist/cli/jarvis-proxy/types.js.map +1 -0
  544. package/dist/cli/license/checker.d.ts +11 -0
  545. package/dist/cli/license/checker.d.ts.map +1 -0
  546. package/dist/cli/license/checker.js +28 -0
  547. package/dist/cli/license/checker.js.map +1 -0
  548. package/dist/cli/license/validator.d.ts +13 -0
  549. package/dist/cli/license/validator.d.ts.map +1 -0
  550. package/dist/cli/license/validator.js +72 -0
  551. package/dist/cli/license/validator.js.map +1 -0
  552. package/dist/cli/providers/anthropic.d.ts +11 -0
  553. package/dist/cli/providers/anthropic.d.ts.map +1 -0
  554. package/dist/cli/providers/anthropic.js +120 -0
  555. package/dist/cli/providers/anthropic.js.map +1 -0
  556. package/dist/cli/providers/model-limits.d.ts +12 -0
  557. package/dist/cli/providers/model-limits.d.ts.map +1 -0
  558. package/dist/cli/providers/model-limits.js +63 -0
  559. package/dist/cli/providers/model-limits.js.map +1 -0
  560. package/dist/cli/providers/ollama.d.ts +37 -0
  561. package/dist/cli/providers/ollama.d.ts.map +1 -0
  562. package/dist/cli/providers/ollama.js +151 -0
  563. package/dist/cli/providers/ollama.js.map +1 -0
  564. package/dist/cli/providers/openai.d.ts +14 -0
  565. package/dist/cli/providers/openai.d.ts.map +1 -0
  566. package/dist/cli/providers/openai.js +319 -0
  567. package/dist/cli/providers/openai.js.map +1 -0
  568. package/dist/cli/providers/rate-limiter.d.ts +51 -0
  569. package/dist/cli/providers/rate-limiter.d.ts.map +1 -0
  570. package/dist/cli/providers/rate-limiter.js +164 -0
  571. package/dist/cli/providers/rate-limiter.js.map +1 -0
  572. package/dist/cli/providers/registry.d.ts +16 -0
  573. package/dist/cli/providers/registry.d.ts.map +1 -0
  574. package/dist/cli/providers/registry.js +99 -0
  575. package/dist/cli/providers/registry.js.map +1 -0
  576. package/dist/cli/providers/types.d.ts +72 -0
  577. package/dist/cli/providers/types.d.ts.map +1 -0
  578. package/dist/cli/providers/types.js +2 -0
  579. package/dist/cli/providers/types.js.map +1 -0
  580. package/dist/cli/sessions/manager.d.ts +69 -0
  581. package/dist/cli/sessions/manager.d.ts.map +1 -0
  582. package/dist/cli/sessions/manager.js +201 -0
  583. package/dist/cli/sessions/manager.js.map +1 -0
  584. package/dist/cli/sessions/session.d.ts +58 -0
  585. package/dist/cli/sessions/session.d.ts.map +1 -0
  586. package/dist/cli/sessions/session.js +74 -0
  587. package/dist/cli/sessions/session.js.map +1 -0
  588. package/dist/cli/sessions/tab-view.d.ts +18 -0
  589. package/dist/cli/sessions/tab-view.d.ts.map +1 -0
  590. package/dist/cli/sessions/tab-view.js +137 -0
  591. package/dist/cli/sessions/tab-view.js.map +1 -0
  592. package/dist/cli/ui/activity.d.ts +81 -0
  593. package/dist/cli/ui/activity.d.ts.map +1 -0
  594. package/dist/cli/ui/activity.js +286 -0
  595. package/dist/cli/ui/activity.js.map +1 -0
  596. package/dist/cli/ui/agent-display.d.ts +24 -0
  597. package/dist/cli/ui/agent-display.d.ts.map +1 -0
  598. package/dist/cli/ui/agent-display.js +36 -0
  599. package/dist/cli/ui/agent-display.js.map +1 -0
  600. package/dist/cli/ui/bottom-chrome.d.ts +121 -0
  601. package/dist/cli/ui/bottom-chrome.d.ts.map +1 -0
  602. package/dist/cli/ui/bottom-chrome.js +428 -0
  603. package/dist/cli/ui/bottom-chrome.js.map +1 -0
  604. package/dist/cli/ui/chat-view.d.ts +10 -0
  605. package/dist/cli/ui/chat-view.d.ts.map +1 -0
  606. package/dist/cli/ui/chat-view.js +237 -0
  607. package/dist/cli/ui/chat-view.js.map +1 -0
  608. package/dist/cli/ui/command-suggest.d.ts +22 -0
  609. package/dist/cli/ui/command-suggest.d.ts.map +1 -0
  610. package/dist/cli/ui/command-suggest.js +118 -0
  611. package/dist/cli/ui/command-suggest.js.map +1 -0
  612. package/dist/cli/ui/input-window.d.ts +145 -0
  613. package/dist/cli/ui/input-window.d.ts.map +1 -0
  614. package/dist/cli/ui/input-window.js +415 -0
  615. package/dist/cli/ui/input-window.js.map +1 -0
  616. package/dist/cli/ui/logo.d.ts +3 -0
  617. package/dist/cli/ui/logo.d.ts.map +1 -0
  618. package/dist/cli/ui/logo.js +25 -0
  619. package/dist/cli/ui/logo.js.map +1 -0
  620. package/dist/cli/ui/plan-display.d.ts +35 -0
  621. package/dist/cli/ui/plan-display.d.ts.map +1 -0
  622. package/dist/cli/ui/plan-display.js +381 -0
  623. package/dist/cli/ui/plan-display.js.map +1 -0
  624. package/dist/cli/ui/progress.d.ts +22 -0
  625. package/dist/cli/ui/progress.d.ts.map +1 -0
  626. package/dist/cli/ui/progress.js +126 -0
  627. package/dist/cli/ui/progress.js.map +1 -0
  628. package/dist/cli/ui/prompt-history.d.ts +37 -0
  629. package/dist/cli/ui/prompt-history.d.ts.map +1 -0
  630. package/dist/cli/ui/prompt-history.js +156 -0
  631. package/dist/cli/ui/prompt-history.js.map +1 -0
  632. package/dist/cli/ui/select-menu.d.ts +45 -0
  633. package/dist/cli/ui/select-menu.d.ts.map +1 -0
  634. package/dist/cli/ui/select-menu.js +330 -0
  635. package/dist/cli/ui/select-menu.js.map +1 -0
  636. package/dist/cli/ui/spinner.d.ts +3 -0
  637. package/dist/cli/ui/spinner.d.ts.map +1 -0
  638. package/dist/cli/ui/spinner.js +14 -0
  639. package/dist/cli/ui/spinner.js.map +1 -0
  640. package/dist/cli/ui/statusbar.d.ts +72 -0
  641. package/dist/cli/ui/statusbar.d.ts.map +1 -0
  642. package/dist/cli/ui/statusbar.js +376 -0
  643. package/dist/cli/ui/statusbar.js.map +1 -0
  644. package/dist/cli/ui/suggestion-panel.d.ts +52 -0
  645. package/dist/cli/ui/suggestion-panel.d.ts.map +1 -0
  646. package/dist/cli/ui/suggestion-panel.js +159 -0
  647. package/dist/cli/ui/suggestion-panel.js.map +1 -0
  648. package/dist/cli/ui/theme.d.ts +20 -0
  649. package/dist/cli/ui/theme.d.ts.map +1 -0
  650. package/dist/cli/ui/theme.js +25 -0
  651. package/dist/cli/ui/theme.js.map +1 -0
  652. package/dist/cli/ui/tool-output.d.ts +31 -0
  653. package/dist/cli/ui/tool-output.d.ts.map +1 -0
  654. package/dist/cli/ui/tool-output.js +204 -0
  655. package/dist/cli/ui/tool-output.js.map +1 -0
  656. package/dist/cli/validation/autofix.d.ts +32 -0
  657. package/dist/cli/validation/autofix.d.ts.map +1 -0
  658. package/dist/cli/validation/autofix.js +148 -0
  659. package/dist/cli/validation/autofix.js.map +1 -0
  660. package/dist/cli/validation/classifier.d.ts +17 -0
  661. package/dist/cli/validation/classifier.d.ts.map +1 -0
  662. package/dist/cli/validation/classifier.js +174 -0
  663. package/dist/cli/validation/classifier.js.map +1 -0
  664. package/dist/cli/validation/criteria.d.ts +22 -0
  665. package/dist/cli/validation/criteria.d.ts.map +1 -0
  666. package/dist/cli/validation/criteria.js +188 -0
  667. package/dist/cli/validation/criteria.js.map +1 -0
  668. package/dist/cli/validation/dynamic-checks.d.ts +16 -0
  669. package/dist/cli/validation/dynamic-checks.d.ts.map +1 -0
  670. package/dist/cli/validation/dynamic-checks.js +109 -0
  671. package/dist/cli/validation/dynamic-checks.js.map +1 -0
  672. package/dist/cli/validation/model.d.ts +16 -0
  673. package/dist/cli/validation/model.d.ts.map +1 -0
  674. package/dist/cli/validation/model.js +59 -0
  675. package/dist/cli/validation/model.js.map +1 -0
  676. package/dist/cli/validation/reporter.d.ts +18 -0
  677. package/dist/cli/validation/reporter.d.ts.map +1 -0
  678. package/dist/cli/validation/reporter.js +209 -0
  679. package/dist/cli/validation/reporter.js.map +1 -0
  680. package/dist/cli/validation/spiral-checks.d.ts +12 -0
  681. package/dist/cli/validation/spiral-checks.d.ts.map +1 -0
  682. package/dist/cli/validation/spiral-checks.js +167 -0
  683. package/dist/cli/validation/spiral-checks.js.map +1 -0
  684. package/dist/cli/validation/static-checks.d.ts +26 -0
  685. package/dist/cli/validation/static-checks.d.ts.map +1 -0
  686. package/dist/cli/validation/static-checks.js +648 -0
  687. package/dist/cli/validation/static-checks.js.map +1 -0
  688. package/dist/cli/validation/stats.d.ts +29 -0
  689. package/dist/cli/validation/stats.d.ts.map +1 -0
  690. package/dist/cli/validation/stats.js +137 -0
  691. package/dist/cli/validation/stats.js.map +1 -0
  692. package/dist/cli/version.d.ts +2 -0
  693. package/dist/cli/version.d.ts.map +1 -0
  694. package/dist/cli/version.js +5 -0
  695. package/dist/cli/version.js.map +1 -0
  696. package/dist/cli/voice/clone-manager.d.ts +19 -0
  697. package/dist/cli/voice/clone-manager.d.ts.map +1 -0
  698. package/dist/cli/voice/clone-manager.js +55 -0
  699. package/dist/cli/voice/clone-manager.js.map +1 -0
  700. package/dist/cli/voice/engine.d.ts +43 -0
  701. package/dist/cli/voice/engine.d.ts.map +1 -0
  702. package/dist/cli/voice/engine.js +109 -0
  703. package/dist/cli/voice/engine.js.map +1 -0
  704. package/dist/cli/voice/whisper-stt.d.ts +28 -0
  705. package/dist/cli/voice/whisper-stt.d.ts.map +1 -0
  706. package/dist/cli/voice/whisper-stt.js +78 -0
  707. package/dist/cli/voice/whisper-stt.js.map +1 -0
  708. package/dist/index.d.ts +3 -0
  709. package/dist/index.d.ts.map +1 -0
  710. package/dist/index.js +35 -0
  711. package/dist/index.js.map +1 -0
  712. package/dist/server.d.ts +8 -0
  713. package/dist/server.d.ts.map +1 -0
  714. package/dist/server.js +44 -0
  715. package/dist/server.js.map +1 -0
  716. package/dist/shared/protocol-types.d.ts +283 -0
  717. package/dist/shared/protocol-types.d.ts.map +1 -0
  718. package/dist/shared/protocol-types.js +9 -0
  719. package/dist/shared/protocol-types.js.map +1 -0
  720. package/dist/spiral/cloud/content-extractor.d.ts +27 -0
  721. package/dist/spiral/cloud/content-extractor.d.ts.map +1 -0
  722. package/dist/spiral/cloud/content-extractor.js +175 -0
  723. package/dist/spiral/cloud/content-extractor.js.map +1 -0
  724. package/dist/spiral/cloud/search-provider.d.ts +22 -0
  725. package/dist/spiral/cloud/search-provider.d.ts.map +1 -0
  726. package/dist/spiral/cloud/search-provider.js +241 -0
  727. package/dist/spiral/cloud/search-provider.js.map +1 -0
  728. package/dist/spiral/cloud/topic-detector.d.ts +25 -0
  729. package/dist/spiral/cloud/topic-detector.d.ts.map +1 -0
  730. package/dist/spiral/cloud/topic-detector.js +196 -0
  731. package/dist/spiral/cloud/topic-detector.js.map +1 -0
  732. package/dist/spiral/cloud/web-enricher.d.ts +58 -0
  733. package/dist/spiral/cloud/web-enricher.d.ts.map +1 -0
  734. package/dist/spiral/cloud/web-enricher.js +176 -0
  735. package/dist/spiral/cloud/web-enricher.js.map +1 -0
  736. package/dist/spiral/compression.d.ts +54 -0
  737. package/dist/spiral/compression.d.ts.map +1 -0
  738. package/dist/spiral/compression.js +175 -0
  739. package/dist/spiral/compression.js.map +1 -0
  740. package/dist/spiral/embeddings.d.ts +30 -0
  741. package/dist/spiral/embeddings.d.ts.map +1 -0
  742. package/dist/spiral/embeddings.js +99 -0
  743. package/dist/spiral/embeddings.js.map +1 -0
  744. package/dist/spiral/engine.d.ts +98 -0
  745. package/dist/spiral/engine.d.ts.map +1 -0
  746. package/dist/spiral/engine.js +330 -0
  747. package/dist/spiral/engine.js.map +1 -0
  748. package/dist/spiral/injection.d.ts +29 -0
  749. package/dist/spiral/injection.d.ts.map +1 -0
  750. package/dist/spiral/injection.js +176 -0
  751. package/dist/spiral/injection.js.map +1 -0
  752. package/dist/spiral/relevance.d.ts +37 -0
  753. package/dist/spiral/relevance.d.ts.map +1 -0
  754. package/dist/spiral/relevance.js +75 -0
  755. package/dist/spiral/relevance.js.map +1 -0
  756. package/dist/storage/database.d.ts +11 -0
  757. package/dist/storage/database.d.ts.map +1 -0
  758. package/dist/storage/database.js +169 -0
  759. package/dist/storage/database.js.map +1 -0
  760. package/dist/storage/edges.d.ts +30 -0
  761. package/dist/storage/edges.d.ts.map +1 -0
  762. package/dist/storage/edges.js +98 -0
  763. package/dist/storage/edges.js.map +1 -0
  764. package/dist/storage/nodes.d.ts +60 -0
  765. package/dist/storage/nodes.d.ts.map +1 -0
  766. package/dist/storage/nodes.js +161 -0
  767. package/dist/storage/nodes.js.map +1 -0
  768. package/dist/storage/vectors.d.ts +25 -0
  769. package/dist/storage/vectors.d.ts.map +1 -0
  770. package/dist/storage/vectors.js +110 -0
  771. package/dist/storage/vectors.js.map +1 -0
  772. package/dist/tools/spiral-compact.d.ts +14 -0
  773. package/dist/tools/spiral-compact.d.ts.map +1 -0
  774. package/dist/tools/spiral-compact.js +14 -0
  775. package/dist/tools/spiral-compact.js.map +1 -0
  776. package/dist/tools/spiral-query.d.ts +18 -0
  777. package/dist/tools/spiral-query.d.ts.map +1 -0
  778. package/dist/tools/spiral-query.js +16 -0
  779. package/dist/tools/spiral-query.js.map +1 -0
  780. package/dist/tools/spiral-relate.d.ts +21 -0
  781. package/dist/tools/spiral-relate.d.ts.map +1 -0
  782. package/dist/tools/spiral-relate.js +21 -0
  783. package/dist/tools/spiral-relate.js.map +1 -0
  784. package/dist/tools/spiral-status.d.ts +8 -0
  785. package/dist/tools/spiral-status.d.ts.map +1 -0
  786. package/dist/tools/spiral-status.js +10 -0
  787. package/dist/tools/spiral-status.js.map +1 -0
  788. package/dist/tools/spiral-store.d.ts +41 -0
  789. package/dist/tools/spiral-store.d.ts.map +1 -0
  790. package/dist/tools/spiral-store.js +22 -0
  791. package/dist/tools/spiral-store.js.map +1 -0
  792. package/dist/types.d.ts +94 -0
  793. package/dist/types.d.ts.map +1 -0
  794. package/dist/types.js +9 -0
  795. package/dist/types.js.map +1 -0
  796. package/dist/utils/config.d.ts +14 -0
  797. package/dist/utils/config.d.ts.map +1 -0
  798. package/dist/utils/config.js +44 -0
  799. package/dist/utils/config.js.map +1 -0
  800. package/dist/utils/logger.d.ts +10 -0
  801. package/dist/utils/logger.d.ts.map +1 -0
  802. package/dist/utils/logger.js +40 -0
  803. package/dist/utils/logger.js.map +1 -0
  804. package/dist/utils/tokens.d.ts +21 -0
  805. package/dist/utils/tokens.d.ts.map +1 -0
  806. package/dist/utils/tokens.js +33 -0
  807. package/dist/utils/tokens.js.map +1 -0
  808. package/package.json +93 -0
@@ -0,0 +1,2099 @@
1
+ export function generateBrainHTML(data) {
2
+ const dataJSON = JSON.stringify(data);
3
+ return `<!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net blob:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws://127.0.0.1:* wss://127.0.0.1:*; img-src 'self' data:; media-src 'self' blob:; worker-src blob:;">
9
+ <title>\u{1F300} HelixMind Brain \u2014 ${data.meta.projectName}</title>
10
+ <style>
11
+ * { margin: 0; padding: 0; box-sizing: border-box; }
12
+ body { background: #050510; color: #e0e0e0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace; overflow: hidden; }
13
+ canvas { display: block; }
14
+
15
+ #ui-overlay {
16
+ position: fixed; top: 0; left: 0; right: 0; bottom: 0;
17
+ pointer-events: none; z-index: 10;
18
+ }
19
+ #ui-overlay > * { pointer-events: auto; }
20
+
21
+ #header {
22
+ position: fixed; top: 16px; left: 16px; z-index: 20;
23
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.15);
24
+ border-radius: 12px; padding: 12px 20px; backdrop-filter: blur(16px);
25
+ }
26
+ #header h1 { font-size: 15px; color: #00d4ff; margin-bottom: 4px; letter-spacing: 1px; }
27
+ #header .stats { font-size: 11px; color: #556; }
28
+ #header .live-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #0f0; margin-right: 6px; animation: livePulse 2s ease infinite; }
29
+ @keyframes livePulse { 0%,100% { opacity: 1; box-shadow: 0 0 4px #0f0; } 50% { opacity: 0.4; box-shadow: none; } }
30
+
31
+ #header .header-controls { display: flex; gap: 6px; margin-top: 6px; align-items: center; }
32
+ #scope-switcher { display: flex; gap: 4px; }
33
+ #scope-switcher .scope-btn {
34
+ padding: 3px 10px; border-radius: 6px; font-size: 10px; cursor: pointer;
35
+ border: 1px solid rgba(0,212,255,0.12); background: rgba(0,212,255,0.03);
36
+ color: #556; transition: all 0.25s; user-select: none;
37
+ }
38
+ #scope-switcher .scope-btn.active {
39
+ background: rgba(0,212,255,0.15); border-color: rgba(0,212,255,0.4); color: #00d4ff; font-weight: 600;
40
+ }
41
+ #scope-switcher .scope-btn.active.project-btn {
42
+ background: rgba(0,212,255,0.15); border-color: rgba(0,212,255,0.4); color: #00d4ff;
43
+ }
44
+ #scope-switcher .scope-btn.active.global-btn {
45
+ background: rgba(108,117,125,0.15); border-color: rgba(108,117,125,0.4); color: #6C757D;
46
+ }
47
+ #scope-switcher .scope-btn:hover:not(.active) { background: rgba(0,212,255,0.08); color: #889; }
48
+
49
+ /* Brain Manager Panel */
50
+ #brain-manager {
51
+ position: fixed; top: 100px; left: 16px; z-index: 20;
52
+ width: 280px; max-height: calc(100vh - 140px); overflow-y: auto;
53
+ background: rgba(5,5,16,0.92); border: 1px solid rgba(0,212,255,0.12);
54
+ border-radius: 12px; padding: 12px; backdrop-filter: blur(16px);
55
+ display: none;
56
+ }
57
+ #brain-manager.open { display: block; }
58
+ #brain-manager h3 {
59
+ font-size: 11px; color: #556; text-transform: uppercase; letter-spacing: 1.5px;
60
+ margin: 0 0 8px 0; padding-bottom: 6px; border-bottom: 1px solid rgba(0,212,255,0.08);
61
+ }
62
+ #brain-manager h3:not(:first-child) { margin-top: 14px; }
63
+ .brain-card {
64
+ background: rgba(0,212,255,0.04); border: 1px solid rgba(0,212,255,0.1);
65
+ border-radius: 8px; padding: 8px 10px; margin-bottom: 6px; cursor: pointer;
66
+ transition: all 0.2s;
67
+ }
68
+ .brain-card:hover { border-color: rgba(0,212,255,0.25); background: rgba(0,212,255,0.08); }
69
+ .brain-card.selected { border-color: rgba(0,212,255,0.5); background: rgba(0,212,255,0.12); }
70
+ .brain-card .bc-top { display: flex; align-items: center; gap: 6px; }
71
+ .brain-card .bc-name {
72
+ font-size: 12px; color: #e0e0e0; flex: 1; outline: none;
73
+ background: transparent; border: none; border-bottom: 1px solid transparent;
74
+ font-family: inherit; padding: 0;
75
+ }
76
+ .brain-card .bc-name:focus { border-bottom-color: rgba(0,212,255,0.4); color: #00d4ff; }
77
+ .brain-card .bc-edit {
78
+ font-size: 10px; cursor: pointer; color: #445; transition: color 0.2s;
79
+ }
80
+ .brain-card .bc-edit:hover { color: #00d4ff; }
81
+ .brain-card .bc-meta { font-size: 10px; color: #445; margin-top: 3px; display: flex; gap: 8px; }
82
+ .brain-card .bc-dot {
83
+ width: 6px; height: 6px; border-radius: 50%; display: inline-block;
84
+ }
85
+ .brain-card .bc-dot.active { background: #0f0; box-shadow: 0 0 4px #0f0; }
86
+ .brain-card .bc-dot.inactive { background: #333; }
87
+
88
+ /* Plan View */
89
+ #plan-view { margin-top: 14px; }
90
+ #plan-view h3 { margin-bottom: 6px; }
91
+ .plan-item {
92
+ font-size: 11px; color: #889; padding: 4px 0; display: flex; align-items: center; gap: 6px;
93
+ }
94
+ .plan-item .pi-icon { font-size: 12px; }
95
+ .plan-item.pending .pi-icon { color: #556; }
96
+ .plan-item.running .pi-icon { color: #FFD700; }
97
+ .plan-item.completed .pi-icon { color: #00ff88; }
98
+ .plan-item.failed .pi-icon { color: #ff4444; }
99
+ .plan-item .pi-text { flex: 1; }
100
+
101
+ /* Brain Manager Toggle (inline in header) */
102
+ #brain-toggle {
103
+ padding: 3px 10px; border-radius: 6px; font-size: 10px; cursor: pointer;
104
+ border: 1px solid rgba(0,212,255,0.12); background: rgba(0,212,255,0.03);
105
+ color: #556; transition: all 0.25s; user-select: none; white-space: nowrap;
106
+ }
107
+ #brain-toggle:hover { background: rgba(0,212,255,0.08); color: #889; }
108
+ #brain-toggle.active { background: rgba(0,212,255,0.15); color: #00d4ff; border-color: rgba(0,212,255,0.4); }
109
+
110
+ #controls {
111
+ position: fixed; top: 16px; right: 16px; z-index: 20;
112
+ display: flex; flex-direction: column; gap: 6px;
113
+ pointer-events: none;
114
+ }
115
+ #controls.collapsed .control-group { display: none; }
116
+ #controls-toggle {
117
+ background: rgba(5,5,16,0.85); border: 1px solid rgba(0,212,255,0.15);
118
+ border-radius: 8px; padding: 6px 12px; cursor: pointer; color: #889;
119
+ font-size: 11px; transition: all 0.2s; pointer-events: auto; align-self: flex-end;
120
+ }
121
+ #controls-toggle:hover { border-color: rgba(0,212,255,0.4); color: #00d4ff; }
122
+ .control-group {
123
+ background: rgba(5,5,16,0.65); border: 1px solid rgba(0,212,255,0.1);
124
+ border-radius: 8px; padding: 8px 12px; backdrop-filter: blur(12px);
125
+ pointer-events: auto;
126
+ }
127
+ .control-group label { font-size: 10px; color: #556; display: block; margin-bottom: 4px; text-transform: uppercase; letter-spacing: 1px; }
128
+
129
+ #search-box {
130
+ position: fixed; top: 16px; left: 50%; transform: translateX(-50%); z-index: 20;
131
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.2);
132
+ border-radius: 20px; padding: 8px 20px; backdrop-filter: blur(16px);
133
+ }
134
+ #search-input {
135
+ background: transparent; border: none; color: #e0e0e0; outline: none;
136
+ font-size: 13px; width: 220px; font-family: inherit;
137
+ }
138
+ #search-input::placeholder { color: #445; }
139
+
140
+ .toggle-btn {
141
+ display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px; margin: 1px;
142
+ background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.08);
143
+ border-radius: 4px; color: #334; cursor: pointer; font-size: 10px;
144
+ transition: all 0.3s; user-select: none; opacity: 0.35;
145
+ }
146
+ .toggle-btn .ldot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; transition: all 0.3s; filter: saturate(0.2) brightness(0.4); }
147
+ .toggle-btn .lcount { font-size: 9px; opacity: 0.5; margin-left: 2px; }
148
+ .toggle-btn.active { opacity: 1; }
149
+ .toggle-btn.active .ldot { filter: saturate(1) brightness(1); }
150
+ .toggle-btn:hover { opacity: 0.8; }
151
+ .toggle-btn[data-edge] { opacity: 0.4; }
152
+ .toggle-btn[data-edge].active { opacity: 1; background: rgba(0,212,255,0.12); border-color: rgba(0,212,255,0.3); color: #00d4ff; }
153
+
154
+ #sidebar {
155
+ position: fixed; right: -380px; top: 0; bottom: 0; width: 380px; z-index: 30;
156
+ background: rgba(5,5,16,0.97); border-left: 1px solid rgba(0,212,255,0.1);
157
+ backdrop-filter: blur(24px); padding: 24px; overflow-y: auto;
158
+ transition: right 0.35s cubic-bezier(0.4,0,0.2,1);
159
+ }
160
+ #sidebar.open { right: 0; }
161
+ #sidebar h2 { color: #00d4ff; font-size: 14px; margin-bottom: 12px; padding-right: 32px; word-break: break-word; }
162
+ #sidebar .node-type { font-size: 10px; padding: 2px 8px; border-radius: 10px; display: inline-block; margin-bottom: 8px; }
163
+ #sidebar .content-preview { font-size: 12px; color: #8899aa; white-space: pre-wrap; word-break: break-word; background: rgba(0,212,255,0.03); border: 1px solid rgba(0,212,255,0.06); padding: 12px; border-radius: 8px; margin: 12px 0; max-height: 200px; overflow-y: auto; line-height: 1.5; }
164
+ #sidebar .relations { font-size: 11px; color: #667; list-style: none; }
165
+ #sidebar .relations li { margin: 4px 0; padding: 4px 0; border-bottom: 1px solid rgba(255,255,255,0.03); }
166
+ #sidebar .close-btn { position: absolute; top: 14px; right: 14px; cursor: pointer; color: #556; font-size: 18px; transition: all 0.2s; z-index: 2; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 6px; background: rgba(5,5,16,0.8); }
167
+ #sidebar .close-btn:hover { color: #fff; background: rgba(255,60,60,0.2); }
168
+ #sidebar .meta-row { font-size: 11px; color: #556; margin: 4px 0; }
169
+
170
+ #findings-panel {
171
+ position: fixed; inset: 0; z-index: 25;
172
+ background: rgba(5,5,16,0.95); backdrop-filter: blur(24px);
173
+ display: none; overflow-y: auto; padding: 40px;
174
+ }
175
+ #findings-panel.open { display: flex; flex-direction: column; align-items: center; }
176
+ #findings-panel .f-inner { width: 100%; max-width: 800px; }
177
+ #findings-panel .f-close { position: fixed; top: 16px; right: 16px; cursor: pointer; color: #556; font-size: 22px; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 8px; background: rgba(5,5,16,0.8); border: 1px solid rgba(0,212,255,0.15); transition: all 0.2s; z-index: 2; }
178
+ #findings-panel .f-close:hover { color: #fff; background: rgba(255,60,60,0.2); }
179
+ #findings-panel h2 { color: #00d4ff; font-size: 13px; margin-bottom: 12px; letter-spacing: 0.5px; }
180
+ #findings-panel .finding-item {
181
+ padding: 10px 12px; margin-bottom: 6px; border-radius: 8px; cursor: pointer;
182
+ background: rgba(0,212,255,0.03); border: 1px solid rgba(0,212,255,0.06);
183
+ transition: all 0.2s; font-size: 11px; line-height: 1.4;
184
+ }
185
+ #findings-panel .finding-item:hover { background: rgba(0,212,255,0.08); border-color: rgba(0,212,255,0.2); }
186
+ #findings-panel .finding-item .f-severity {
187
+ font-size: 9px; padding: 1px 6px; border-radius: 8px; display: inline-block; margin-bottom: 4px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.5px;
188
+ }
189
+ #findings-panel .finding-item .f-severity.critical { background: rgba(255,0,0,0.15); color: #ff4444; }
190
+ #findings-panel .finding-item .f-severity.high { background: rgba(255,100,0,0.15); color: #ff6600; }
191
+ #findings-panel .finding-item .f-severity.medium { background: rgba(255,200,0,0.15); color: #ffaa00; }
192
+ #findings-panel .finding-item .f-severity.low { background: rgba(0,200,100,0.15); color: #00cc66; }
193
+ #findings-panel .finding-item .f-severity.info { background: rgba(0,180,255,0.15); color: #00b4ff; }
194
+ #findings-panel .finding-item .f-text { color: #aab; word-break: break-word; }
195
+ #findings-panel .finding-item .f-file { color: #556; font-size: 10px; margin-top: 3px; font-family: monospace; }
196
+ #findings-panel .f-session { color: #667; font-size: 10px; margin-bottom: 8px; }
197
+ #findings-panel .f-count { color: #556; font-size: 11px; margin-bottom: 8px; }
198
+ #findings-panel .f-empty { color: #445; font-size: 12px; text-align: center; margin-top: 40px; }
199
+ #findings-toggle {
200
+ position: fixed; left: 16px; bottom: 16px; z-index: 26;
201
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.15);
202
+ border-radius: 8px; padding: 6px 12px; cursor: pointer; color: #889;
203
+ font-size: 11px; transition: all 0.2s;
204
+ }
205
+ #findings-toggle:hover { border-color: rgba(0,212,255,0.4); color: #00d4ff; }
206
+ #findings-toggle .badge { background: #ff4444; color: white; font-size: 9px; padding: 1px 5px; border-radius: 8px; margin-left: 4px; }
207
+
208
+ #models-toggle {
209
+ position: fixed; left: 120px; bottom: 16px; z-index: 26;
210
+ background: rgba(255,40,40,0.12); border: 1px solid rgba(255,40,40,0.35);
211
+ border-radius: 8px; padding: 6px 12px; cursor: pointer; color: #ff6666;
212
+ font-size: 11px; transition: all 0.2s;
213
+ }
214
+ #models-toggle:hover { background: rgba(255,40,40,0.25); border-color: rgba(255,40,40,0.6); color: #ff8888; }
215
+ #models-toggle.online { background: rgba(0,255,100,0.08); border-color: rgba(0,255,100,0.25); color: #00ff66; }
216
+ #models-toggle.online:hover { background: rgba(0,255,100,0.15); border-color: rgba(0,255,100,0.4); }
217
+ #models-toggle .status-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 4px; }
218
+ #models-toggle .status-dot.online { background: #0f0; box-shadow: 0 0 4px #0f0; }
219
+ #models-toggle .status-dot.offline { background: #ff4444; box-shadow: 0 0 4px #ff4444; animation: livePulse 1.5s ease infinite; }
220
+
221
+ #models-panel {
222
+ position: fixed; inset: 0; z-index: 28;
223
+ background: rgba(5,5,16,0.95); backdrop-filter: blur(24px);
224
+ display: none; overflow-y: auto; padding: 40px;
225
+ }
226
+ #models-panel.open { display: flex; flex-direction: column; align-items: center; }
227
+ #models-panel > *:not(.mp-close) { width: 100%; max-width: 800px; }
228
+ #models-panel h2 { color: #00d4ff; font-size: 14px; margin-bottom: 6px; letter-spacing: 0.5px; }
229
+ #models-panel .mp-subtitle { color: #556; font-size: 11px; margin-bottom: 14px; }
230
+ #models-panel .mp-close { position: fixed; top: 16px; right: 16px; cursor: pointer; color: #556; font-size: 22px; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 8px; background: rgba(5,5,16,0.8); border: 1px solid rgba(0,212,255,0.15); transition: all 0.2s; z-index: 2; }
231
+ #models-panel .mp-close:hover { color: #fff; background: rgba(255,60,60,0.2); }
232
+ #models-panel .mp-section { margin-bottom: 16px; }
233
+ #models-panel .mp-section-title { font-size: 10px; color: #556; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; padding-bottom: 4px; border-bottom: 1px solid rgba(0,212,255,0.06); }
234
+
235
+ #gpu-filter { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
236
+ #gpu-filter .gpu-btn {
237
+ padding: 4px 10px; border-radius: 6px; font-size: 10px; cursor: pointer;
238
+ background: rgba(0,212,255,0.05); border: 1px solid rgba(0,212,255,0.12);
239
+ color: #778; transition: all 0.2s; user-select: none;
240
+ }
241
+ #gpu-filter .gpu-btn.active { background: rgba(0,212,255,0.15); border-color: rgba(0,212,255,0.4); color: #00d4ff; }
242
+ #gpu-filter .gpu-btn:hover { background: rgba(0,212,255,0.1); color: #aad; }
243
+
244
+ .model-card {
245
+ padding: 10px 12px; margin-bottom: 6px; border-radius: 8px;
246
+ background: rgba(0,212,255,0.03); border: 1px solid rgba(0,212,255,0.06);
247
+ transition: all 0.2s; font-size: 11px;
248
+ }
249
+ .model-card:hover { background: rgba(0,212,255,0.08); border-color: rgba(0,212,255,0.2); }
250
+ .model-card .mc-name { color: #e0e0e0; font-weight: 600; font-size: 12px; }
251
+ .model-card .mc-meta { color: #556; font-size: 10px; margin-top: 2px; }
252
+ .model-card .mc-desc { color: #889; font-size: 10px; margin-top: 4px; }
253
+ .model-card .mc-status { font-size: 9px; padding: 1px 6px; border-radius: 8px; display: inline-block; margin-top: 4px; }
254
+ .model-card .mc-status.running { background: rgba(0,255,0,0.12); color: #0f0; }
255
+ .model-card .mc-status.installed { background: rgba(0,212,255,0.12); color: #00d4ff; }
256
+ .model-card .mc-status.available { background: rgba(255,170,0,0.12); color: #ffaa00; }
257
+ .model-card .mc-actions { margin-top: 6px; display: flex; gap: 6px; }
258
+ .model-card .mc-btn {
259
+ padding: 3px 10px; border-radius: 5px; font-size: 10px; cursor: pointer;
260
+ border: 1px solid rgba(0,212,255,0.2); background: rgba(0,212,255,0.08);
261
+ color: #00d4ff; transition: all 0.2s;
262
+ }
263
+ .model-card .mc-btn:hover { background: rgba(0,212,255,0.2); }
264
+ .model-card .mc-btn.primary { border-color: rgba(0,255,100,0.3); background: rgba(0,255,100,0.08); color: #00ff66; }
265
+ .model-card .mc-btn.primary:hover { background: rgba(0,255,100,0.2); }
266
+ .model-card .mc-btn.danger { border-color: rgba(255,60,60,0.2); background: rgba(255,60,60,0.08); color: #ff4444; }
267
+ .model-card .mc-btn.danger:hover { background: rgba(255,60,60,0.2); }
268
+ .model-card .mc-btn:disabled { opacity: 0.4; cursor: not-allowed; }
269
+ .model-card .mc-progress { margin-top: 6px; display: none; }
270
+ .model-card .mc-progress.active { display: block; }
271
+ .model-card .mc-progress-bar { height: 3px; background: rgba(0,212,255,0.15); border-radius: 2px; overflow: hidden; }
272
+ .model-card .mc-progress-fill { height: 100%; background: linear-gradient(90deg, #00d4ff, #00ff88); border-radius: 2px; width: 0%; transition: width 0.3s; }
273
+ .model-card .mc-progress-text { font-size: 9px; color: #556; margin-top: 2px; }
274
+
275
+ #help-btn {
276
+ position: fixed; bottom: 16px; left: 50%; transform: translateX(calc(-50% + 180px)); z-index: 20;
277
+ width: 28px; height: 28px; border-radius: 50%;
278
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.15);
279
+ color: #556; font-size: 13px; cursor: pointer;
280
+ display: flex; align-items: center; justify-content: center;
281
+ backdrop-filter: blur(16px); transition: all 0.3s;
282
+ }
283
+ #help-btn:hover { border-color: rgba(0,212,255,0.4); color: #00d4ff; }
284
+
285
+ #help-overlay {
286
+ position: fixed; inset: 0; z-index: 50;
287
+ background: rgba(5,5,16,0.85); backdrop-filter: blur(12px);
288
+ display: none; align-items: center; justify-content: center;
289
+ }
290
+ #help-overlay.open { display: flex; }
291
+ #help-box {
292
+ background: rgba(10,10,24,0.98); border: 1px solid rgba(0,212,255,0.2);
293
+ border-radius: 16px; padding: 28px 36px; max-width: 520px; width: 90%;
294
+ box-shadow: 0 16px 64px rgba(0,0,0,0.6);
295
+ }
296
+ #help-box h3 { color: #00d4ff; font-size: 15px; margin-bottom: 16px; letter-spacing: 1px; }
297
+ #help-box .help-section { margin-bottom: 14px; }
298
+ #help-box .help-section h4 { color: #889; font-size: 10px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }
299
+ #help-box .help-row { display: flex; justify-content: space-between; align-items: center; padding: 3px 0; font-size: 12px; }
300
+ #help-box .help-key { color: #00d4ff; font-family: monospace; background: rgba(0,212,255,0.08); padding: 1px 6px; border-radius: 3px; border: 1px solid rgba(0,212,255,0.15); font-size: 11px; }
301
+ #help-box .help-desc { color: #778; }
302
+ #help-box .help-close { margin-top: 16px; text-align: center; font-size: 11px; color: #445; }
303
+
304
+ #tooltip {
305
+ position: fixed; display: none; z-index: 25;
306
+ background: rgba(5,5,16,0.97); border: 1px solid rgba(0,212,255,0.25);
307
+ border-radius: 10px; padding: 12px 16px; pointer-events: none;
308
+ backdrop-filter: blur(16px); max-width: 320px;
309
+ box-shadow: 0 8px 32px rgba(0,0,0,0.5), 0 0 16px rgba(0,212,255,0.08);
310
+ }
311
+ #tooltip .tt-name { color: #00d4ff; font-size: 13px; font-weight: 600; }
312
+ #tooltip .tt-type { font-size: 10px; color: #556; margin-top: 2px; }
313
+ #tooltip .tt-meta { color: #667; font-size: 11px; margin-top: 4px; }
314
+
315
+ #legend {
316
+ position: fixed; bottom: 56px; left: 16px; z-index: 20;
317
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.1);
318
+ border-radius: 8px; padding: 10px 14px; backdrop-filter: blur(16px);
319
+ font-size: 10px; color: #556;
320
+ }
321
+ #legend .item { display: flex; align-items: center; gap: 6px; margin: 2px 0; }
322
+ #legend .dot { width: 8px; height: 8px; border-radius: 50%; box-shadow: 0 0 6px currentColor; }
323
+
324
+ #status {
325
+ position: fixed; bottom: 16px; right: 16px; z-index: 20;
326
+ background: rgba(5,5,16,0.9); border: 1px solid rgba(0,212,255,0.1);
327
+ border-radius: 8px; padding: 8px 14px; backdrop-filter: blur(16px);
328
+ font-size: 10px; color: #556;
329
+ }
330
+
331
+ #voice-panel {
332
+ position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%); z-index: 35;
333
+ background: rgba(5,5,16,0.95); border: 1px solid rgba(0,212,255,0.15);
334
+ border-radius: 16px; padding: 10px 16px; backdrop-filter: blur(24px);
335
+ display: flex; align-items: center; gap: 12px;
336
+ box-shadow: 0 8px 40px rgba(0,0,0,0.5);
337
+ transition: all 0.3s cubic-bezier(0.4,0,0.2,1);
338
+ }
339
+ #voice-panel.recording { border-color: rgba(255,60,60,0.5); box-shadow: 0 0 30px rgba(255,60,60,0.15), 0 8px 40px rgba(0,0,0,0.5); }
340
+ #voice-btn {
341
+ width: 42px; height: 42px; border-radius: 50%; border: 2px solid rgba(0,212,255,0.3);
342
+ background: rgba(0,212,255,0.08); cursor: pointer; display: flex;
343
+ align-items: center; justify-content: center; transition: all 0.3s;
344
+ color: #556; font-size: 18px; flex-shrink: 0;
345
+ }
346
+ #voice-btn:hover { border-color: rgba(0,212,255,0.6); background: rgba(0,212,255,0.15); color: #00d4ff; }
347
+ #voice-btn.recording { border-color: #ff3c3c; background: rgba(255,60,60,0.15); color: #ff3c3c; animation: voicePulse 1.2s ease infinite; }
348
+ @keyframes voicePulse { 0%,100% { box-shadow: 0 0 0 0 rgba(255,60,60,0.4); } 50% { box-shadow: 0 0 0 10px rgba(255,60,60,0); } }
349
+ #voice-transcript { flex: 1; min-width: 200px; max-width: 500px; font-size: 13px; color: #e0e0e0; min-height: 20px; max-height: 60px; overflow-y: auto; word-break: break-word; }
350
+ #voice-transcript.placeholder { color: #445; font-style: italic; }
351
+ #voice-send { padding: 6px 14px; border-radius: 8px; border: 1px solid rgba(0,212,255,0.3); background: rgba(0,212,255,0.1); color: #00d4ff; cursor: pointer; font-size: 12px; font-weight: 600; transition: all 0.2s; flex-shrink: 0; display: none; }
352
+ #voice-send:hover { background: rgba(0,212,255,0.25); border-color: rgba(0,212,255,0.5); }
353
+ #voice-send.visible { display: block; }
354
+ #voice-waveform { display: none; align-items: center; gap: 2px; height: 24px; flex-shrink: 0; }
355
+ #voice-panel.recording #voice-waveform { display: flex; }
356
+ .waveform-bar { width: 3px; background: #ff3c3c; border-radius: 2px; animation: waveformPulse 0.6s ease-in-out infinite alternate; }
357
+ @keyframes waveformPulse { from { height: 4px; opacity: 0.4; } to { height: 20px; opacity: 1; } }
358
+ #voice-lang { background: transparent; border: 1px solid rgba(0,212,255,0.15); border-radius: 4px; color: #556; font-size: 9px; padding: 2px 4px; cursor: pointer; flex-shrink: 0; }
359
+ #voice-lang:focus { outline: none; border-color: rgba(0,212,255,0.4); }
360
+ #voice-status { font-size: 9px; color: #445; flex-shrink: 0; min-width: 40px; text-align: center; }
361
+
362
+ #web-knowledge-container {
363
+ position: fixed; top: 80px; right: 16px; z-index: 40;
364
+ display: flex; flex-direction: column; gap: 8px;
365
+ pointer-events: none; max-width: 340px;
366
+ }
367
+ .web-knowledge-popup {
368
+ background: rgba(5,5,16,0.95); border: 1px solid rgba(0,255,136,0.3);
369
+ border-radius: 12px; padding: 14px 18px; backdrop-filter: blur(24px);
370
+ box-shadow: 0 4px 24px rgba(0,255,136,0.15), 0 0 60px rgba(0,255,136,0.05);
371
+ animation: wkSlideIn 0.5s cubic-bezier(0.16,1,0.3,1) forwards;
372
+ opacity: 0; transform: translateX(60px); pointer-events: auto;
373
+ transition: opacity 0.4s ease, transform 0.4s ease;
374
+ }
375
+ .web-knowledge-popup.removing { opacity: 0 !important; transform: translateX(60px) !important; }
376
+ .web-knowledge-popup .wk-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
377
+ .web-knowledge-popup .wk-icon { font-size: 16px; }
378
+ .web-knowledge-popup .wk-title { font-size: 11px; color: #00ff88; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; }
379
+ .web-knowledge-popup .wk-topic { font-size: 13px; color: #e0e0e0; font-weight: 500; margin-bottom: 4px; }
380
+ .web-knowledge-popup .wk-summary { font-size: 11px; color: #8899aa; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
381
+ .web-knowledge-popup .wk-source { font-size: 9px; color: #445566; margin-top: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
382
+ .web-knowledge-popup .wk-progress { height: 2px; background: rgba(0,255,136,0.1); border-radius: 1px; margin-top: 8px; overflow: hidden; }
383
+ .web-knowledge-popup .wk-progress-bar { height: 100%; background: linear-gradient(90deg, #00ff88, #00d4ff); border-radius: 1px; width: 100%; animation: wkShrink 6s linear forwards; }
384
+ @keyframes wkSlideIn { from { opacity: 0; transform: translateX(60px) scale(0.95); } to { opacity: 1; transform: translateX(0) scale(1); } }
385
+ @keyframes wkShrink { from { width: 100%; } to { width: 0%; } }
386
+
387
+ #holo-overlay {
388
+ position: fixed; inset: 0; pointer-events: none; z-index: 1;
389
+ background:
390
+ repeating-linear-gradient(
391
+ 0deg,
392
+ transparent,
393
+ transparent 2px,
394
+ rgba(0,255,200,0.015) 2px,
395
+ rgba(0,255,200,0.015) 4px
396
+ ),
397
+ radial-gradient(
398
+ ellipse at center,
399
+ transparent 50%,
400
+ rgba(0,0,0,0.4) 100%
401
+ );
402
+ }
403
+ </style>
404
+ </head>
405
+ <body>
406
+
407
+ <div id="holo-overlay"></div>
408
+
409
+ <div id="header">
410
+ <h1><span class="live-dot"></span>\u{1F300} HelixMind Brain</h1>
411
+ <div class="stats" id="stats-text">${data.meta.totalNodes} nodes \u00B7 ${data.meta.totalEdges} connections${data.meta.webKnowledgeCount > 0 ? ` \\u00B7 ${data.meta.webKnowledgeCount} web` : ''} \u00B7 ${data.meta.projectName}</div>
412
+ <div class="header-controls">
413
+ <div id="scope-switcher">
414
+ <span class="scope-btn project-btn${data.meta.brainScope === 'project' ? ' active' : ''}" data-scope="project">\u{1F4C1} Local</span>
415
+ <span class="scope-btn global-btn${data.meta.brainScope !== 'project' ? ' active' : ''}" data-scope="global">\u{1F310} Global</span>
416
+ </div>
417
+ <div id="brain-toggle">\u{1F9E0} Brains</div>
418
+ </div>
419
+ </div>
420
+
421
+ <div id="brain-manager">
422
+ <h3>\u{1F310} Global</h3>
423
+ <div id="bm-global"></div>
424
+ <h3>\u{1F4C1} Local</h3>
425
+ <div id="bm-local"></div>
426
+ <div id="plan-view">
427
+ <h3>\u{1F4CB} Plan</h3>
428
+ <div id="plan-items"><div class="plan-item pending"><span class="pi-icon">\u25CB</span><span class="pi-text" style="color:#445">No active tasks</span></div></div>
429
+ </div>
430
+ </div>
431
+
432
+ <div id="search-box"><input id="search-input" type="text" placeholder="Search nodes..." aria-label="Search nodes" /></div>
433
+
434
+ <div id="controls" class="collapsed">
435
+ <button id="controls-toggle">\u2699 Filters</button>
436
+ <div class="control-group">
437
+ <label>Levels</label>
438
+ <span class="toggle-btn active" data-level="5" data-color="#FF6B6B"><span class="ldot" style="background:#FF6B6B;box-shadow:0 0 6px #FF6B6B"></span>L5 Deep<span class="lcount" id="lc5"></span></span>
439
+ <span class="toggle-btn active" data-level="4" data-color="#00FFFF"><span class="ldot" style="background:#00FFFF;box-shadow:0 0 6px #00FFFF"></span>L4 Archive<span class="lcount" id="lc4"></span></span>
440
+ <span class="toggle-btn active" data-level="3" data-color="#7B68EE"><span class="ldot" style="background:#7B68EE;box-shadow:0 0 6px #7B68EE"></span>L3 Ref<span class="lcount" id="lc3"></span></span>
441
+ <span class="toggle-btn active" data-level="2" data-color="#00ff88"><span class="ldot" style="background:#00ff88;box-shadow:0 0 6px #00ff88"></span>L2 Active<span class="lcount" id="lc2"></span></span>
442
+ <span class="toggle-btn active" data-level="1" data-color="#E040FB"><span class="ldot" style="background:#E040FB;box-shadow:0 0 6px #E040FB"></span>L1 Focus<span class="lcount" id="lc1"></span></span>
443
+ <span class="toggle-btn active" data-level="6" data-color="#FFD700"><span class="ldot" style="background:#FFD700;box-shadow:0 0 6px #FFD700"></span>L6 Web<span class="lcount" id="lc6"></span></span>
444
+ </div>
445
+ <div class="control-group">
446
+ <label>Relations</label>
447
+ <span class="toggle-btn active" data-edge="all">All</span>
448
+ <span class="toggle-btn" data-edge="references">Refs</span>
449
+ <span class="toggle-btn" data-edge="depends_on">Depends</span>
450
+ <span class="toggle-btn" data-edge="related_to">Related</span>
451
+ <span class="toggle-btn" data-edge="evolved_from">Evolved</span>
452
+ <span class="toggle-btn" data-edge="supports">Supports</span>
453
+ <span class="toggle-btn" data-edge="extends">Extends</span>
454
+ <span class="toggle-btn" data-edge="implements">Impl</span>
455
+ <span class="toggle-btn" data-edge="uses">Uses</span>
456
+ <span class="toggle-btn" data-edge="imports">Imports</span>
457
+ </div>
458
+ </div>
459
+
460
+ <div id="sidebar"><span class="close-btn" id="sidebar-close">\u2715</span><div id="sidebar-content"></div></div>
461
+ <div id="tooltip"><div class="tt-name"></div><div class="tt-type"></div><div class="tt-meta"></div></div>
462
+
463
+ <div id="legend">
464
+ <div class="item"><span class="dot" style="color:#E040FB"></span> L1 Focus</div>
465
+ <div class="item"><span class="dot" style="color:#00FF88"></span> L2 Active</div>
466
+ <div class="item"><span class="dot" style="color:#7B68EE"></span> L3 Reference</div>
467
+ <div class="item"><span class="dot" style="color:#00FFFF"></span> L4 Archive</div>
468
+ <div class="item"><span class="dot" style="color:#FF6B6B"></span> L5 Deep Archive</div>
469
+ <div class="item"><span class="dot" style="color:#FFD700"></span> L6 Web Knowledge</div>
470
+ <div style="margin-top:4px;font-size:9px;color:#445;border-top:1px solid rgba(255,255,255,0.04);padding-top:4px">Edges = node level colors</div>
471
+ </div>
472
+
473
+ <div id="status"><span id="node-count">0</span> nodes \u00B7 <span id="fps-counter">60</span> fps \u00B7 <span id="web-count" style="color:#FFAA00"></span></div>
474
+ <div id="web-knowledge-container"></div>
475
+
476
+ <div id="findings-panel">
477
+ <span class="f-close" id="findings-close">\u2715</span>
478
+ <div class="f-inner">
479
+ <h2>\u{1F50D} Agent Findings</h2>
480
+ <div class="f-count" id="findings-count"></div>
481
+ <div id="findings-list"><div class="f-empty">No findings yet.<br>Start /security or /auto to see live results.</div></div>
482
+ </div>
483
+ </div>
484
+ <button id="findings-toggle" title="Toggle findings panel">\u{1F50D} Findings <span class="badge" id="findings-badge" style="display:none">0</span></button>
485
+ <button id="models-toggle" title="Local LLM Models"><span class="status-dot offline" id="ollama-dot"></span>\u{1F9E0} Models</button>
486
+
487
+ <div id="models-panel">
488
+ <span class="mp-close" id="models-close">\u2715</span>
489
+ <h2>\u{1F9E0} LLM Models</h2>
490
+ <div class="mp-subtitle" id="ollama-status">Checking Ollama...</div>
491
+ <div class="mp-section" id="cloud-section"><div class="mp-section-title">\u{2601} Cloud Models</div><div id="cloud-models"><div style="color:#445;font-size:11px">Loading cloud models...</div></div></div>
492
+ <div class="mp-section"><div class="mp-section-title">GPU / VRAM Filter</div>
493
+ <div id="gpu-filter">
494
+ <span class="gpu-btn" data-vram="8">8 GB</span><span class="gpu-btn" data-vram="12">12 GB</span>
495
+ <span class="gpu-btn" data-vram="16">16 GB</span><span class="gpu-btn" data-vram="24">24 GB</span>
496
+ <span class="gpu-btn active" data-vram="32">32 GB (RTX 5090)</span><span class="gpu-btn" data-vram="48">48 GB</span>
497
+ </div>
498
+ </div>
499
+ <div class="mp-section" id="running-section" style="display:none"><div class="mp-section-title">\u{25B6} Running Models</div><div id="running-models"></div></div>
500
+ <div class="mp-section" id="installed-section"><div class="mp-section-title">\u{2705} Installed Models</div><div id="installed-models"><div style="color:#445;font-size:11px">Loading...</div></div></div>
501
+ <div class="mp-section"><div class="mp-section-title">\u{2B50} Recommended for Coding</div><div id="recommended-models"></div></div>
502
+ </div>
503
+
504
+ <button id="help-btn" title="Keyboard shortcuts & controls">?</button>
505
+ <div id="help-overlay">
506
+ <div id="help-box">
507
+ <h3>\u{1F300} HelixMind Brain \u2014 Controls</h3>
508
+ <div class="help-section"><h4>Navigation</h4>
509
+ <div class="help-row"><span class="help-key">Left Drag</span> <span class="help-desc">Rotate view</span></div>
510
+ <div class="help-row"><span class="help-key">Right Drag</span> <span class="help-desc">Pan view</span></div>
511
+ <div class="help-row"><span class="help-key">Scroll</span> <span class="help-desc">Zoom in / out</span></div>
512
+ </div>
513
+ <div class="help-section"><h4>Nodes</h4>
514
+ <div class="help-row"><span class="help-key">Click</span> <span class="help-desc">Select node \u2192 zoom in + details</span></div>
515
+ <div class="help-row"><span class="help-key">Hover</span> <span class="help-desc">Preview node info</span></div>
516
+ </div>
517
+ <div class="help-section"><h4>Keyboard</h4>
518
+ <div class="help-row"><span class="help-key">?</span> <span class="help-desc">Toggle this help</span></div>
519
+ <div class="help-row"><span class="help-key">Esc</span> <span class="help-desc">Close sidebar / help</span></div>
520
+ </div>
521
+ <div class="help-close">Press <span style="color:#00d4ff">?</span> or <span style="color:#00d4ff">Esc</span> to close</div>
522
+ </div>
523
+ </div>
524
+
525
+ <div id="voice-panel">
526
+ <button id="voice-btn" title="Voice Input">\u{1F3A4}</button>
527
+ <div id="voice-waveform"></div>
528
+ <div id="voice-transcript" class="placeholder">Click mic to speak...</div>
529
+ <select id="voice-lang" title="Language" aria-label="Voice language"><option value="en-US">EN</option><option value="de-DE">DE</option></select>
530
+ <span id="voice-status"></span>
531
+ <button id="voice-send">\u{2191} Send</button>
532
+ </div>
533
+
534
+ <script type="importmap">
535
+ { "imports": {
536
+ "three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
537
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
538
+ } }
539
+ </script>
540
+
541
+ <script type="module">
542
+ import * as THREE from 'three';
543
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
544
+ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
545
+ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
546
+ import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
547
+
548
+ // ===== DATA =====
549
+ let BRAIN_DATA = ${dataJSON};
550
+
551
+ // ===== CONSTANTS =====
552
+ const LVL_HEX = { 1: 0xE040FB, 2: 0x00FF88, 3: 0x7B68EE, 4: 0x00FFFF, 5: 0xFF6B6B, 6: 0xFFD700, 7: 0xFF00FF };
553
+ const LVL_CSS = { 1: '#E040FB', 2: '#00FF88', 3: '#7B68EE', 4: '#00FFFF', 5: '#FF6B6B', 6: '#FFD700', 7: '#FF00FF' };
554
+ const LVL_SIZE = { 1:6, 2:7, 3:12, 4:16, 5:22, 6:10, 7:8 };
555
+ let curSpread=600;
556
+ const BASE_SPREAD=400, REP=28000, ATT=0.002, ILEN=100, DAMP=0.82, GCELL=160, MAX_E=18000;
557
+ const EDGE_COL={references:'#7B68EE',depends_on:'#E040FB',related_to:'#556',evolved_from:'#00FFFF',supports:'#00FF88',extends:'#FFD700',implements:'#FF6B6B',uses:'#00d4ff',imports:'#00ff88',default:'#445'};
558
+
559
+ function srand(s) { const x=Math.sin(s*9301+49297)*49297; return x-Math.floor(x); }
560
+ function esc(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
561
+
562
+ // ===== RENDERER (sharp: AA + native pixel ratio) =====
563
+ const R = new THREE.WebGLRenderer({ antialias:true, alpha:true, powerPreference:'high-performance' });
564
+ R.setSize(innerWidth, innerHeight);
565
+ R.setPixelRatio(Math.min(window.devicePixelRatio, 2));
566
+ R.toneMapping = THREE.ACESFilmicToneMapping;
567
+ R.toneMappingExposure = 1.1;
568
+ document.body.prepend(R.domElement);
569
+
570
+ const scene = new THREE.Scene();
571
+ scene.background = new THREE.Color('#050510');
572
+ scene.fog = new THREE.FogExp2('#050510', 0.000012);
573
+
574
+ const cam = new THREE.PerspectiveCamera(55, innerWidth/innerHeight, 1, 30000);
575
+ cam.position.set(0, 500, 3000);
576
+
577
+ const ctrl = new OrbitControls(cam, R.domElement);
578
+ ctrl.target.set(0,0,0);
579
+ ctrl.enableDamping = true;
580
+ ctrl.dampingFactor = 0.06;
581
+ ctrl.autoRotate = true;
582
+ ctrl.autoRotateSpeed = 0.08;
583
+ ctrl.minDistance = 80;
584
+ ctrl.maxDistance = 15000;
585
+ ctrl.maxPolarAngle = Math.PI * 0.85;
586
+ ctrl.minPolarAngle = Math.PI * 0.15;
587
+ ctrl.update();
588
+
589
+ // ===== POST-PROCESSING (UnrealBloom at full res for sharp output) =====
590
+ const dpr = Math.min(window.devicePixelRatio, 2);
591
+ const rtW = Math.floor(innerWidth * dpr), rtH = Math.floor(innerHeight * dpr);
592
+ const fullRT = new THREE.WebGLRenderTarget(rtW, rtH, { type: THREE.HalfFloatType });
593
+ const composer = new EffectComposer(R, fullRT);
594
+ composer.addPass(new RenderPass(scene, cam));
595
+ const bloom = new UnrealBloomPass(
596
+ new THREE.Vector2(rtW, rtH),
597
+ 0.5, // strength
598
+ 0.3, // radius
599
+ 0.85 // threshold
600
+ );
601
+ composer.addPass(bloom);
602
+
603
+ // ===== STARS (static — dual layer for parallax depth) =====
604
+ const stP = new Float32Array(1500*3);
605
+ for(let i=0;i<1500;i++){ stP[i*3]=(srand(i*31)-.5)*5000; stP[i*3+1]=(srand(i*37)-.5)*5000; stP[i*3+2]=(srand(i*41)-.5)*5000; }
606
+ const stG = new THREE.BufferGeometry();
607
+ stG.setAttribute('position', new THREE.BufferAttribute(stP,3));
608
+ scene.add(new THREE.Points(stG, new THREE.PointsMaterial({ size:1.2, color:'#223344', transparent:true, opacity:0.5, blending:THREE.AdditiveBlending, depthWrite:false, sizeAttenuation:true })));
609
+ // Second layer: larger dim stars for depth
610
+ const st2P = new Float32Array(200*3);
611
+ for(let i=0;i<200;i++){ st2P[i*3]=(srand(i*71)-.5)*8000; st2P[i*3+1]=(srand(i*73)-.5)*8000; st2P[i*3+2]=(srand(i*79)-.5)*8000; }
612
+ const st2G = new THREE.BufferGeometry();
613
+ st2G.setAttribute('position', new THREE.BufferAttribute(st2P,3));
614
+ scene.add(new THREE.Points(st2G, new THREE.PointsMaterial({ size:2.5, color:'#1a2a3a', transparent:true, opacity:0.25, blending:THREE.AdditiveBlending, depthWrite:false, sizeAttenuation:true })));
615
+
616
+ // ===== STATIC SHADERS (zero per-frame cost) =====
617
+ const nMat = new THREE.ShaderMaterial({
618
+ vertexShader: \`
619
+ attribute float aSize;
620
+ attribute vec3 aColor;
621
+ attribute float aHL;
622
+ varying vec3 vC;
623
+ varying float vA;
624
+ void main(){
625
+ vC=aColor; vA=aHL;
626
+ vec4 mv=modelViewMatrix*vec4(position,1.0);
627
+ gl_PointSize=aSize*aHL*(1200.0/-mv.z);
628
+ gl_Position=projectionMatrix*mv;
629
+ }\`,
630
+ fragmentShader: \`
631
+ varying vec3 vC;
632
+ varying float vA;
633
+ void main(){
634
+ vec2 c=gl_PointCoord-vec2(.5);
635
+ float d=length(c);
636
+ if(d>.5)discard;
637
+ float i=exp(-d*d*50.0)*0.9+exp(-d*d*8.0)*0.4+exp(-d*d*2.5)*0.15;
638
+ float core=exp(-d*d*50.0);
639
+ gl_FragColor=vec4(vC*(1.0+core*2.0),i*vA);
640
+ }\`,
641
+ transparent:true, depthWrite:false, blending:THREE.AdditiveBlending
642
+ });
643
+
644
+ const eMat = new THREE.ShaderMaterial({
645
+ uniforms: { uBreath: { value: 1.0 } },
646
+ vertexShader: \`
647
+ attribute vec3 color;
648
+ attribute float aA;
649
+ varying vec3 vC;
650
+ varying float vA;
651
+ void main(){ vC=color; vA=aA; gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0); }\`,
652
+ fragmentShader: \`
653
+ uniform float uBreath;
654
+ varying vec3 vC;
655
+ varying float vA;
656
+ void main(){ gl_FragColor=vec4(vC,vA*uBreath); }\`,
657
+ transparent:true, depthWrite:false, blending:THREE.AdditiveBlending
658
+ });
659
+
660
+ // ===== SIGNAL PARTICLE MATERIAL (neural impulses) =====
661
+ const sigMat = new THREE.ShaderMaterial({
662
+ vertexShader: \`
663
+ attribute float aSize;
664
+ attribute vec3 aColor;
665
+ varying vec3 vC;
666
+ void main(){
667
+ vC=aColor;
668
+ vec4 mv=modelViewMatrix*vec4(position,1.0);
669
+ gl_PointSize=aSize*(1200.0/-mv.z);
670
+ gl_Position=projectionMatrix*mv;
671
+ }\`,
672
+ fragmentShader: \`
673
+ varying vec3 vC;
674
+ void main(){
675
+ vec2 c=gl_PointCoord-vec2(.5);
676
+ float d=length(c);
677
+ if(d>.5)discard;
678
+ float glow=exp(-d*d*20.0)+exp(-d*d*5.0)*0.4;
679
+ gl_FragColor=vec4(vC*2.0,glow*0.9);
680
+ }\`,
681
+ transparent:true, depthWrite:false, blending:THREE.AdditiveBlending
682
+ });
683
+
684
+ // ===== SCENE STATE =====
685
+ let nPts=null, nGeo=null, eLines=null, eGeo=null;
686
+ let sigPts=null, sigGeo=null, sigData=[];
687
+ const SIG_COUNT=80;
688
+ let nodeVisEdges={};
689
+ let nodes=[], pos=[], byLvl={}, adj={}, nMap={}, nEdgeMap={}, vEdges=[], nC=0, eC=0;
690
+ const tc=new THREE.Color(), tc2=new THREE.Color();
691
+ let layoutWorker=null, lastNodeIds='';
692
+
693
+ // ===== WEB WORKER FORCE SIMULATION (non-blocking) =====
694
+ const workerCode=\`
695
+ self.onmessage=function(ev){
696
+ const{nC,levels,lvlCounts,ePairs,SPREAD,REP,ATT,ILEN,DAMP,GCELL,STEPS}=ev.data;
697
+ function srand(s){const x=Math.sin(s*9301+49297)*49297;return x-Math.floor(x);}
698
+
699
+ // Level centroids along a HELIX path (organic, non-spherical)
700
+ const uLvl=[...new Set(levels)].sort().filter(l=>l!==6); // L6 gets satellite treatment
701
+ const centroids={};
702
+ const GA=2.399963;
703
+ uLvl.forEach((lv,i)=>{
704
+ const t=(i+0.5)/Math.max(uLvl.length,1);
705
+ const height=(t-0.5)*SPREAD*2.4;
706
+ const radius=SPREAD*0.7+SPREAD*0.15*Math.sin(t*Math.PI*2);
707
+ const angle=GA*i*2.5;
708
+ centroids[lv]={x:radius*Math.cos(angle), y:height, z:radius*Math.sin(angle)};
709
+ });
710
+
711
+ // L6 Web Knowledge: multiple satellite clusters distributed AROUND the brain
712
+ const l6Indices=[];
713
+ for(let i=0;i<nC;i++) if(levels[i]===6) l6Indices.push(i);
714
+ const SAT_SIZE=7; // nodes per satellite cluster
715
+ const numSats=Math.max(1,Math.ceil(l6Indices.length/SAT_SIZE));
716
+ const satCentroids=[];
717
+ for(let s=0;s<numSats;s++){
718
+ // Distribute on sphere using fibonacci/golden angle for even spacing
719
+ const phi=Math.acos(1-2*(s+0.5)/numSats);
720
+ const theta=GA*s*3.7;
721
+ const satR=SPREAD*1.6; // orbit distance — outside main brain
722
+ satCentroids.push({
723
+ x:satR*Math.sin(phi)*Math.cos(theta),
724
+ y:satR*Math.cos(phi)*0.8, // slightly flattened
725
+ z:satR*Math.sin(phi)*Math.sin(theta)
726
+ });
727
+ }
728
+ // Map each L6 node to its satellite cluster
729
+ const l6Sat={};
730
+ l6Indices.forEach((ni,idx)=>{ l6Sat[ni]=Math.floor(idx/SAT_SIZE)%numSats; });
731
+
732
+ // Init: L1 scattered, L6 at satellite positions, L2-L5 near helix centroids
733
+ const P=new Float64Array(nC*3), V=new Float64Array(nC*3);
734
+ for(let i=0;i<nC;i++){
735
+ const lv=levels[i];
736
+ const phi=Math.acos(2*srand(i*13)-1), th=srand(i*17)*Math.PI*2;
737
+ if(lv===1){
738
+ // L1 Focus: scatter across entire volume, driven by edges
739
+ const r=SPREAD*0.9*Math.cbrt(srand(i*23));
740
+ P[i*3]=r*Math.sin(phi)*Math.cos(th);
741
+ P[i*3+1]=r*Math.sin(phi)*Math.sin(th);
742
+ P[i*3+2]=r*Math.cos(phi);
743
+ } else if(lv===6){
744
+ // L6 Web: tight cluster at assigned satellite position
745
+ const sc=satCentroids[l6Sat[i]]||satCentroids[0];
746
+ const r=SPREAD*0.06*Math.cbrt(srand(i*23));
747
+ P[i*3]=sc.x+r*Math.sin(phi)*Math.cos(th);
748
+ P[i*3+1]=sc.y+r*Math.sin(phi)*Math.sin(th);
749
+ P[i*3+2]=sc.z+r*Math.cos(phi);
750
+ } else {
751
+ const c=centroids[lv]||{x:0,y:0,z:0};
752
+ const lc=lvlCounts[lv]||1;
753
+ const initR=SPREAD*0.15*Math.sqrt(Math.max(lc/50,1));
754
+ const r=initR*Math.cbrt(srand(i*23));
755
+ P[i*3]=c.x+r*Math.sin(phi)*Math.cos(th);
756
+ P[i*3+1]=c.y+r*Math.sin(phi)*Math.sin(th);
757
+ P[i*3+2]=c.z+r*Math.cos(phi);
758
+ }
759
+ }
760
+
761
+ const CPULL=0.005;
762
+
763
+ for(let step=0;step<STEPS;step++){
764
+ const decay=1-step/STEPS*0.3;
765
+
766
+ // Grid-based repulsion
767
+ const grid={};
768
+ for(let i=0;i<nC;i++){
769
+ const k=Math.floor(P[i*3]/GCELL)+','+Math.floor(P[i*3+1]/GCELL)+','+Math.floor(P[i*3+2]/GCELL);
770
+ if(!grid[k])grid[k]=[];grid[k].push(i);
771
+ }
772
+ for(let i=0;i<nC;i++){
773
+ const gx=Math.floor(P[i*3]/GCELL),gy=Math.floor(P[i*3+1]/GCELL),gz=Math.floor(P[i*3+2]/GCELL);
774
+ for(let dx=-1;dx<=1;dx++)for(let dy=-1;dy<=1;dy++)for(let dz=-1;dz<=1;dz++){
775
+ const c=grid[(gx+dx)+','+(gy+dy)+','+(gz+dz)];
776
+ if(!c)continue;
777
+ for(const j of c){
778
+ if(j<=i)continue;
779
+ const ddx=P[i*3]-P[j*3],ddy=P[i*3+1]-P[j*3+1],ddz=P[i*3+2]-P[j*3+2];
780
+ const dSq=ddx*ddx+ddy*ddy+ddz*ddz+1,d=Math.sqrt(dSq),f=REP*decay/dSq;
781
+ const fx=ddx*f/d,fy=ddy*f/d,fz=ddz*f/d;
782
+ V[i*3]+=fx;V[i*3+1]+=fy;V[i*3+2]+=fz;
783
+ V[j*3]-=fx;V[j*3+1]-=fy;V[j*3+2]-=fz;
784
+ }
785
+ }
786
+ }
787
+
788
+ // Edge attraction (same-level 2x, cross-level 0.6x)
789
+ for(const[si,ti]of ePairs){
790
+ const ddx=P[ti*3]-P[si*3],ddy=P[ti*3+1]-P[si*3+1],ddz=P[ti*3+2]-P[si*3+2];
791
+ const d=Math.sqrt(ddx*ddx+ddy*ddy+ddz*ddz)+0.1;
792
+ const sameLvl=levels[si]===levels[ti]?2.0:0.6;
793
+ const f=(d-ILEN)*ATT*sameLvl;
794
+ const fx=ddx/d*f,fy=ddy/d*f,fz=ddz/d*f;
795
+ V[si*3]+=fx;V[si*3+1]+=fy;V[si*3+2]+=fz;
796
+ V[ti*3]-=fx;V[ti*3+1]-=fy;V[ti*3+2]-=fz;
797
+ }
798
+
799
+ // Cluster pull: L1 free, L6 toward satellites, L2-L5 toward helix centroids
800
+ for(let i=0;i<nC;i++){
801
+ if(levels[i]===1)continue;
802
+ if(levels[i]===6){
803
+ // L6: pull toward assigned satellite centroid (stronger to keep orbit)
804
+ const sc=satCentroids[l6Sat[i]];
805
+ if(sc){
806
+ V[i*3]+=(sc.x-P[i*3])*CPULL*2;
807
+ V[i*3+1]+=(sc.y-P[i*3+1])*CPULL*2;
808
+ V[i*3+2]+=(sc.z-P[i*3+2])*CPULL*2;
809
+ }
810
+ continue;
811
+ }
812
+ const c=centroids[levels[i]];
813
+ if(!c)continue;
814
+ V[i*3]+=(c.x-P[i*3])*CPULL;
815
+ V[i*3+1]+=(c.y-P[i*3+1])*CPULL;
816
+ V[i*3+2]+=(c.z-P[i*3+2])*CPULL;
817
+ }
818
+
819
+ // Apply velocity + damping
820
+ for(let i=0;i<nC*3;i++){P[i]+=V[i];V[i]*=DAMP;}
821
+ }
822
+
823
+ const result=new Float32Array(nC*3);
824
+ for(let i=0;i<nC*3;i++)result[i]=P[i];
825
+ self.postMessage({positions:result},[result.buffer]);
826
+ };
827
+ \`;
828
+ const workerBlob=new Blob([workerCode],{type:'application/javascript'});
829
+ const workerURL=URL.createObjectURL(workerBlob);
830
+
831
+ // ===== BUILD SCENE (geometry from positions) =====
832
+ function buildGeometry(P){
833
+ if(nGeo){nGeo.dispose();scene.remove(nPts);}
834
+ if(eGeo){eGeo.dispose();scene.remove(eLines);}
835
+
836
+ pos=new Array(nC);
837
+ for(let i=0;i<nC;i++) pos[i]=new THREE.Vector3(P[i*3],P[i*3+1],P[i*3+2]);
838
+
839
+ // Move energy core + rings to node centroid
840
+ let cx=0,cy=0,cz=0;
841
+ for(let i=0;i<nC;i++){cx+=P[i*3];cy+=P[i*3+1];cz+=P[i*3+2];}
842
+ cx/=nC;cy/=nC;cz/=nC;
843
+ core.position.set(cx,cy,cz);
844
+ core2.position.set(cx,cy,cz);
845
+ orbCx=cx;orbCy=cy;orbCz=cz;
846
+
847
+ // --- NODES ---
848
+ nGeo=new THREE.BufferGeometry();
849
+ const nP=new Float32Array(nC*3), nCol=new Float32Array(nC*3), nSz=new Float32Array(nC), nHL=new Float32Array(nC);
850
+ for(let i=0;i<nC;i++){
851
+ const p=pos[i], n=nodes[i];
852
+ nP[i*3]=p.x; nP[i*3+1]=p.y; nP[i*3+2]=p.z;
853
+ // Distance from centroid for fade effect
854
+ const dx=p.x-cx,dy=p.y-cy,dz=p.z-cz;
855
+ const dist=Math.sqrt(dx*dx+dy*dy+dz*dz);
856
+ const maxD=curSpread*1.2;
857
+ const distRatio=Math.min(dist/maxD,1); // 0=center, 1=far edge
858
+ if(n.level===1){
859
+ // L1 Focus: primarily magenta/fuchsia (characteristic L1) with subtle hue variation
860
+ const h=0.78+srand(i*137+42)*0.1; // hue 0.78-0.88 (magenta–fuchsia range)
861
+ const s=0.7+srand(i*173)*0.3;
862
+ const l=0.45+srand(i*211)*0.2;
863
+ tc.setHSL(h,s,l);
864
+ } else {
865
+ tc.set(LVL_HEX[n.level]||0x00FFFF);
866
+ }
867
+ // Distant nodes fade to light blue/gray
868
+ if(distRatio>0.55){
869
+ const fade=Math.min((distRatio-0.55)/0.45,1); // 0 at 55%, 1 at 100%
870
+ const coolC=new THREE.Color().setHSL(0.58,0.15+0.1*(1-fade),0.65+fade*0.15);
871
+ tc.lerp(coolC,fade*0.85);
872
+ }
873
+ nCol[i*3]=tc.r; nCol[i*3+1]=tc.g; nCol[i*3+2]=tc.b;
874
+ nSz[i]=LVL_SIZE[n.level]||36;
875
+ nHL[i]=1.0;
876
+ }
877
+ nGeo.setAttribute('position',new THREE.BufferAttribute(nP,3));
878
+ nGeo.setAttribute('aColor',new THREE.BufferAttribute(nCol,3));
879
+ nGeo.setAttribute('aSize',new THREE.BufferAttribute(nSz,1));
880
+ nGeo.setAttribute('aHL',new THREE.BufferAttribute(nHL,1));
881
+ nPts=new THREE.Points(nGeo,nMat);
882
+ scene.add(nPts);
883
+
884
+ // --- EDGES (level-based colors, improved alpha) ---
885
+ const crossE=[], sameE=[];
886
+ BRAIN_DATA.edges.forEach((e,i)=>{
887
+ const si=nMap[e.source], ti=nMap[e.target];
888
+ if(si===undefined||ti===undefined) return;
889
+ const obj={si,ti,w:e.weight,t:e.type,i,cross:nodes[si].level!==nodes[ti].level};
890
+ if(obj.cross) crossE.push(obj); else sameE.push(obj);
891
+ });
892
+ crossE.sort((a,b)=>b.w-a.w);
893
+ sameE.sort((a,b)=>b.w-a.w);
894
+ // Always include ALL cross-level edges (bridges between clusters), fill rest with same-level
895
+ vEdges=[...crossE, ...sameE].slice(0,MAX_E);
896
+ eC=vEdges.length;
897
+
898
+ const eP=new Float32Array(eC*6), eCol=new Float32Array(eC*6), eA=new Float32Array(eC*2);
899
+ const ec=new THREE.Color(), aS=Math.min(1.0,2500/eC);
900
+ for(let i=0;i<eC;i++){
901
+ const{si,ti,w,cross}=vEdges[i];
902
+ const s=pos[si], d=pos[ti], o=i*6;
903
+ eP[o]=s.x; eP[o+1]=s.y; eP[o+2]=s.z;
904
+ eP[o+3]=d.x; eP[o+4]=d.y; eP[o+5]=d.z;
905
+ // Edge color = per-node color (L1 uses individual rainbow, others level hex)
906
+ eCol[o]=nCol[si*3]; eCol[o+1]=nCol[si*3+1]; eCol[o+2]=nCol[si*3+2];
907
+ eCol[o+3]=nCol[ti*3]; eCol[o+4]=nCol[ti*3+1]; eCol[o+5]=nCol[ti*3+2];
908
+ // Cross-level edges (bridges) get alpha boost so satellite connections are visible
909
+ const ba=cross?(0.08+w*0.2):(0.04+w*0.1);
910
+ eA[i*2]=ba*aS; eA[i*2+1]=ba*aS;
911
+ }
912
+ eGeo=new THREE.BufferGeometry();
913
+ eGeo.setAttribute('position',new THREE.BufferAttribute(eP,3));
914
+ eGeo.setAttribute('color',new THREE.BufferAttribute(eCol,3));
915
+ eGeo.setAttribute('aA',new THREE.BufferAttribute(eA,1));
916
+ eLines=new THREE.LineSegments(eGeo,eMat);
917
+ scene.add(eLines);
918
+
919
+ // HUD
920
+ document.getElementById('node-count').textContent=nC;
921
+ const wC=BRAIN_DATA.meta.webKnowledgeCount||nodes.filter(n=>n.level===6).length;
922
+ document.getElementById('stats-text').textContent=nC+' nodes \\u00B7 '+BRAIN_DATA.edges.length+' connections'+(wC>0?' \\u00B7 '+wC+' web':'')+' \\u00B7 '+BRAIN_DATA.meta.projectName;
923
+ document.getElementById('web-count').textContent=wC>0?'\\u{1F310} '+wC+' web':'';
924
+ for(let lv=1;lv<=6;lv++){const el=document.getElementById('lc'+lv);if(el)el.textContent=(byLvl[lv]||[]).length;}
925
+
926
+ // Build node→visible-edge map for signal chaining
927
+ nodeVisEdges={};
928
+ vEdges.forEach((v,idx)=>{
929
+ if(!nodeVisEdges[v.si])nodeVisEdges[v.si]=[];
930
+ if(!nodeVisEdges[v.ti])nodeVisEdges[v.ti]=[];
931
+ nodeVisEdges[v.si].push(idx);
932
+ nodeVisEdges[v.ti].push(idx);
933
+ });
934
+
935
+ lvlToggles={};
936
+ document.querySelectorAll('[data-level]').forEach(b=>{lvlToggles[parseInt(b.dataset.level)]=b.classList.contains('active');updateBtnStyle(b);});
937
+ hovIdx=-1; selIdx=-1;
938
+ initSignals();
939
+ }
940
+
941
+ // ===== SIGNAL PARTICLES (neural impulses traveling along edges) =====
942
+ function initSignals(){
943
+ if(sigPts){sigGeo.dispose();scene.remove(sigPts);sigPts=null;}
944
+ if(eC===0||!pos||pos.length===0)return;
945
+ sigData=[];
946
+ sigGeo=new THREE.BufferGeometry();
947
+ const sp=new Float32Array(SIG_COUNT*3);
948
+ const sc=new Float32Array(SIG_COUNT*3);
949
+ const ss=new Float32Array(SIG_COUNT);
950
+ for(let i=0;i<SIG_COUNT;i++){
951
+ const ei=Math.floor(Math.random()*eC);
952
+ sigData.push({edge:ei, progress:Math.random(), speed:0.25+Math.random()*0.55, forward:Math.random()>0.5});
953
+ ss[i]=6+Math.random()*5;
954
+ }
955
+ sigGeo.setAttribute('position',new THREE.BufferAttribute(sp,3));
956
+ sigGeo.setAttribute('aColor',new THREE.BufferAttribute(sc,3));
957
+ sigGeo.setAttribute('aSize',new THREE.BufferAttribute(ss,1));
958
+ sigPts=new THREE.Points(sigGeo,sigMat);
959
+ scene.add(sigPts);
960
+ }
961
+
962
+ function updateSignals(dt){
963
+ if(!sigGeo||eC===0||!pos||pos.length===0)return;
964
+ const sp=sigGeo.attributes.position;
965
+ const sc=sigGeo.attributes.aColor;
966
+ for(let i=0;i<SIG_COUNT;i++){
967
+ const s=sigData[i];
968
+ s.progress+=s.speed*dt;
969
+ if(s.progress>=1.0){
970
+ const{si,ti}=vEdges[s.edge];
971
+ const endN=s.forward?ti:si;
972
+ const nxt=nodeVisEdges[endN];
973
+ if(nxt&&nxt.length>0){
974
+ const newEi=nxt[Math.floor(Math.random()*nxt.length)];
975
+ s.edge=newEi;
976
+ s.forward=vEdges[newEi].si===endN;
977
+ }else{
978
+ s.edge=Math.floor(Math.random()*eC);
979
+ s.forward=Math.random()>0.5;
980
+ }
981
+ s.progress=0;
982
+ s.speed=0.25+Math.random()*0.55;
983
+ }
984
+ const{si,ti}=vEdges[s.edge];
985
+ const p=s.forward?s.progress:1-s.progress;
986
+ const src=pos[si],tgt=pos[ti];
987
+ if(!src||!tgt)continue;
988
+ sp.array[i*3]=src.x+(tgt.x-src.x)*p;
989
+ sp.array[i*3+1]=src.y+(tgt.y-src.y)*p;
990
+ sp.array[i*3+2]=src.z+(tgt.z-src.z)*p;
991
+ // Signal color from per-node colors (matches edge gradient)
992
+ if(nGeo){const nc=nGeo.getAttribute('aColor');tc.setRGB(nc.array[si*3],nc.array[si*3+1],nc.array[si*3+2]);tc2.setRGB(nc.array[ti*3],nc.array[ti*3+1],nc.array[ti*3+2]);}
993
+ else{tc.set(LVL_HEX[nodes[si].level]||0xE040FB);tc2.set(LVL_HEX[nodes[ti].level]||0xE040FB);}
994
+ tc.lerp(tc2,p);
995
+ sc.array[i*3]=tc.r;sc.array[i*3+1]=tc.g;sc.array[i*3+2]=tc.b;
996
+ }
997
+ sp.needsUpdate=true;sc.needsUpdate=true;
998
+ }
999
+
1000
+ // ===== MAIN BUILD (prepares data, launches worker) =====
1001
+ let hasInitialCamera=false;
1002
+ function buildScene(){
1003
+ nodes=BRAIN_DATA.nodes; nC=nodes.length;
1004
+ byLvl={};
1005
+ nodes.forEach((n,i)=>{const lv=n.level||3;if(!byLvl[lv])byLvl[lv]=[];byLvl[lv].push(i);});
1006
+
1007
+ // Adjacency
1008
+ nMap={};nodes.forEach((n,i)=>{nMap[n.id]=i;});
1009
+ adj={};nEdgeMap={};
1010
+ const ePairs=[];
1011
+ BRAIN_DATA.edges.forEach((e,ei)=>{
1012
+ const si=nMap[e.source],ti=nMap[e.target];
1013
+ if(si===undefined||ti===undefined)return;
1014
+ if(!adj[si])adj[si]=new Set();if(!adj[ti])adj[ti]=new Set();
1015
+ adj[si].add(ti);adj[ti].add(si);
1016
+ if(!nEdgeMap[si])nEdgeMap[si]=[];if(!nEdgeMap[ti])nEdgeMap[ti]=[];
1017
+ nEdgeMap[si].push(ei);nEdgeMap[ti].push(ei);
1018
+ ePairs.push([si,ti]);
1019
+ });
1020
+
1021
+ // Node levels array for worker
1022
+ const levels=new Int8Array(nC);
1023
+ for(let i=0;i<nC;i++) levels[i]=nodes[i].level||3;
1024
+
1025
+ // Adaptive steps: fewer for large graphs
1026
+ const STEPS=nC>2000?300:nC>1000?500:800;
1027
+
1028
+ // Terminate previous worker if running
1029
+ if(layoutWorker){layoutWorker.terminate();layoutWorker=null;}
1030
+
1031
+ curSpread=BASE_SPREAD+Math.sqrt(nC)*25;
1032
+ layoutWorker=new Worker(workerURL);
1033
+ layoutWorker.onmessage=function(ev){
1034
+ buildGeometry(ev.data.positions);
1035
+ // Only set camera on first build — subsequent updates preserve current view
1036
+ if(!hasInitialCamera){
1037
+ cam.position.set(0,curSpread*0.3,curSpread*1.8);
1038
+ ctrl.target.set(0,0,0);
1039
+ hasInitialCamera=true;
1040
+ }
1041
+ layoutWorker.terminate();layoutWorker=null;
1042
+ };
1043
+ const lvlCounts={};for(let i=0;i<nC;i++){const lv=levels[i];lvlCounts[lv]=(lvlCounts[lv]||0)+1;}
1044
+ layoutWorker.postMessage({nC,levels:Array.from(levels),lvlCounts,ePairs,SPREAD:curSpread,REP,ATT,ILEN,DAMP,GCELL,STEPS});
1045
+ }
1046
+
1047
+ // ===== INTERACTION =====
1048
+ const ray=new THREE.Raycaster();
1049
+ ray.params.Points={threshold:8};
1050
+ const mouse=new THREE.Vector2();
1051
+ let hovIdx=-1, selIdx=-1, camTw=null, lvlToggles={};
1052
+
1053
+ const ttEl=document.getElementById('tooltip');
1054
+ const ttN=ttEl.querySelector('.tt-name'), ttT=ttEl.querySelector('.tt-type'), ttM=ttEl.querySelector('.tt-meta');
1055
+
1056
+ R.domElement.addEventListener('mousemove',(e)=>{
1057
+ mouse.x=(e.clientX/innerWidth)*2-1;
1058
+ mouse.y=-(e.clientY/innerHeight)*2+1;
1059
+ if(!nPts)return;
1060
+ ray.setFromCamera(mouse,cam);
1061
+ const hits=ray.intersectObject(nPts);
1062
+ const prev=hovIdx;
1063
+ if(hits.length>0){
1064
+ hovIdx=hits[0].index;
1065
+ R.domElement.style.cursor='pointer';
1066
+ const n=nodes[hovIdx];
1067
+ ttN.textContent=n.label;
1068
+ ttT.textContent=(n.level===6?'\\u{1F310} Web Knowledge':n.type+' \\u00B7 Level '+n.level);
1069
+ ttM.textContent='Relevance: '+n.relevanceScore.toFixed(2)+' \\u00B7 '+n.createdAt.slice(0,10)+(n.webTopic?' \\u00B7 '+n.webTopic:'');
1070
+ ttEl.style.display='block';
1071
+ ttEl.style.left=(e.clientX+14)+'px';
1072
+ ttEl.style.top=(e.clientY-10)+'px';
1073
+ } else {
1074
+ hovIdx=-1; R.domElement.style.cursor='default'; ttEl.style.display='none';
1075
+ }
1076
+ if(prev!==hovIdx) updateHL();
1077
+ });
1078
+
1079
+ // Drag detection: only select on clean click, not after camera drag
1080
+ let mdX=0,mdY=0,isDrag=false;
1081
+ R.domElement.addEventListener('mousedown',(e)=>{ mdX=e.clientX; mdY=e.clientY; isDrag=false; });
1082
+ R.domElement.addEventListener('mousemove',(e)=>{
1083
+ if(Math.abs(e.clientX-mdX)+Math.abs(e.clientY-mdY)>5) isDrag=true;
1084
+ });
1085
+ R.domElement.addEventListener('click',()=>{
1086
+ if(isDrag) return; // ignore drag-releases
1087
+ if(hovIdx>=0){
1088
+ selIdx=hovIdx;
1089
+ showSidebar(nodes[selIdx]);
1090
+ ctrl.autoRotate=false;
1091
+ const np=pos[selIdx], dir=cam.position.clone().sub(np).normalize();
1092
+ camTw={ sP:cam.position.clone(), sL:ctrl.target.clone(), tP:np.clone().add(dir.multiplyScalar(70)), tL:np.clone(), p:0 };
1093
+ updateHL();
1094
+ } else if(selIdx>=0){
1095
+ // Click on empty space while node selected → deselect + zoom out
1096
+ closeSB();
1097
+ }
1098
+ });
1099
+
1100
+ // ===== HIGHLIGHTS (only on interaction, zero per-frame cost) =====
1101
+ function updateHL(){
1102
+ if(!nGeo||!eGeo)return;
1103
+ const ha=nGeo.attributes.aHL;
1104
+ const ea=eGeo.attributes.aA;
1105
+ const sq=document.getElementById('search-input').value.toLowerCase();
1106
+ const hasS=sq.length>0, hasF=selIdx>=0;
1107
+ const cHov=hovIdx>=0&&adj[hovIdx]?adj[hovIdx]:new Set();
1108
+ const cSel=selIdx>=0&&adj[selIdx]?adj[selIdx]:new Set();
1109
+
1110
+ for(let i=0;i<nC;i++){
1111
+ let h=1.0;
1112
+ const lv=nodes[i].level;
1113
+ if(lvlToggles[lv]===false){ ha.array[i]=0.05; continue; }
1114
+ if(hasS){ h=nodes[i].label.toLowerCase().includes(sq)||nodes[i].content.toLowerCase().includes(sq)?1.0:0.12; }
1115
+ if(hasF){ h=cSel.has(i)||i===selIdx?1.0:0.1; }
1116
+ if(hovIdx>=0){ if(i===hovIdx)h=Math.max(h,1.5); else if(cHov.has(i))h=Math.max(h,1.2); }
1117
+ ha.array[i]=h;
1118
+ }
1119
+ ha.needsUpdate=true;
1120
+
1121
+ const aET=getActiveET();
1122
+ const allActive=aET===null;
1123
+ const aS=Math.min(1.0,2500/eC);
1124
+ const glowMul=allActive?2.5:1.0;
1125
+ for(let i=0;i<eC;i++){
1126
+ const{si,ti,w,t,cross}=vEdges[i];
1127
+ const sLv=nodes[si].level, tLv=nodes[ti].level;
1128
+ if(lvlToggles[sLv]===false||lvlToggles[tLv]===false){ ea.array[i*2]=0; ea.array[i*2+1]=0; continue; }
1129
+ let a=(cross?(0.08+w*0.2):(0.04+w*0.1))*aS*glowMul;
1130
+ if(aET!==null&&!aET.has(t)) a=0;
1131
+ if(hasF){ a=(si===selIdx||ti===selIdx)?0.4+w*0.3:0.01; }
1132
+ if(hovIdx>=0){ if(si===hovIdx||ti===hovIdx) a=Math.max(a,0.35+w*0.3); }
1133
+ if(hasS){ if(!nodes[si].label.toLowerCase().includes(sq)&&!nodes[ti].label.toLowerCase().includes(sq)) a=0.01; }
1134
+ ea.array[i*2]=a; ea.array[i*2+1]=a;
1135
+ }
1136
+ ea.needsUpdate=true;
1137
+ }
1138
+
1139
+ function getActiveET(){
1140
+ const all=document.querySelector('[data-edge="all"]');
1141
+ if(all&&all.classList.contains('active'))return null;
1142
+ const s=new Set();
1143
+ document.querySelectorAll('[data-edge].active').forEach(b=>{ if(b.dataset.edge!=='all')s.add(b.dataset.edge); });
1144
+ return s.size>0?s:null;
1145
+ }
1146
+
1147
+ // ===== SIDEBAR =====
1148
+ function showSidebar(node){
1149
+ const sb=document.getElementById('sidebar'), ct=document.getElementById('sidebar-content');
1150
+ const tCol={code:'#00FFFF',module:'#00CED1',architecture:'#7B68EE',pattern:'#00ff88',error:'#ff4444',decision:'#ffdd00',summary:'#888',web_knowledge:'#FFD700'};
1151
+ const col=tCol[node.type]||'#888';
1152
+ const cE=BRAIN_DATA.edges.filter(e=>e.source===node.id||e.target===node.id);
1153
+ const rH=cE.map(e=>{
1154
+ const oId=e.source===node.id?e.target:e.source;
1155
+ const oI=nMap[oId]; const oL=oI!==undefined?nodes[oI].label:oId.slice(0,8);
1156
+ const eC2=EDGE_COL[e.type]||EDGE_COL.default;
1157
+ return '<li><span style="color:'+eC2+'">'+e.type+'</span> \\u2192 '+esc(oL)+'</li>';
1158
+ }).join('');
1159
+ const lvN=node.level===6?'Web Knowledge':'L'+node.level;
1160
+ const isW=node.level===6;
1161
+ let wH='';
1162
+ if(isW){
1163
+ if(node.webTopic) wH+='<div class="meta-row" style="color:#FFAA00">\\u{1F310} Topic: '+esc(node.webTopic)+'</div>';
1164
+ if(node.webSource) wH+='<div class="meta-row"><a href="'+esc(node.webSource)+'" target="_blank" style="color:#668;text-decoration:underline">\\u{1F517} '+esc(node.webSource)+'</a></div>';
1165
+ }
1166
+ ct.innerHTML='<h2>'+esc(node.label)+'</h2>'+'<span class="node-type" style="background:'+col+'15;color:'+col+';border:1px solid '+col+'33">'+(isW?'\\u{1F310} Web':node.type)+' \\u00B7 '+lvN+'</span>'+wH+'<div class="content-preview">'+esc(node.content)+'</div>'+'<div class="meta-row">Relevance: '+node.relevanceScore.toFixed(3)+'</div>'+'<div class="meta-row">Created: '+node.createdAt.slice(0,10)+'</div>'+'<div class="meta-row">Accessed: '+node.lastAccessed.slice(0,10)+'</div>'+(cE.length>0?'<h3 style="margin-top:16px;font-size:11px;color:#556;text-transform:uppercase;letter-spacing:1px">Relations ('+cE.length+')</h3><ul class="relations">'+rH+'</ul>':'');
1167
+ sb.classList.add('open');
1168
+ }
1169
+
1170
+ function closeSB(evt){
1171
+ document.getElementById('sidebar').classList.remove('open');
1172
+ selIdx=-1; updateHL();
1173
+ if(!(evt&&evt.shiftKey)){
1174
+ ctrl.autoRotate=true;
1175
+ camTw={ sP:cam.position.clone(), sL:ctrl.target.clone(), tP:new THREE.Vector3(0,curSpread*0.3,curSpread*1.8), tL:new THREE.Vector3(0,0,0), p:0 };
1176
+ }
1177
+ }
1178
+ document.getElementById('sidebar-close').addEventListener('click',(e)=>closeSB(e));
1179
+
1180
+ // ===== HELP =====
1181
+ const helpO=document.getElementById('help-overlay');
1182
+ document.getElementById('help-btn').addEventListener('click',()=>helpO.classList.toggle('open'));
1183
+ helpO.addEventListener('click',(e)=>{ if(e.target===helpO)helpO.classList.remove('open'); });
1184
+
1185
+ // ===== KEYBOARD =====
1186
+ document.addEventListener('keydown',(e)=>{
1187
+ if(e.target.tagName==='INPUT'||e.target.tagName==='SELECT'||e.target.tagName==='TEXTAREA')return;
1188
+ if(e.key==='?'||(e.key==='/'&&e.shiftKey)){ e.preventDefault(); helpO.classList.toggle('open'); }
1189
+ if(e.key==='Escape'){
1190
+ if(helpO.classList.contains('open')) helpO.classList.remove('open');
1191
+ else if(document.getElementById('sidebar').classList.contains('open')) closeSB(e);
1192
+ }
1193
+ });
1194
+
1195
+ // ===== SEARCH =====
1196
+ document.getElementById('search-input').addEventListener('input',()=>updateHL());
1197
+
1198
+ // ===== LEVEL TOGGLES =====
1199
+ function updateBtnStyle(b){
1200
+ const a=b.classList.contains('active'), c=b.dataset.color||'#00d4ff';
1201
+ if(a){ b.style.borderColor=c+'80'; b.style.color=c; b.style.background=c+'18'; b.style.textShadow='0 0 8px '+c+'60'; }
1202
+ else{ b.style.borderColor='rgba(255,255,255,0.06)'; b.style.color='#334'; b.style.background='rgba(255,255,255,0.02)'; b.style.textShadow='none'; }
1203
+ }
1204
+ document.querySelectorAll('[data-level]').forEach(b=>{
1205
+ updateBtnStyle(b);
1206
+ b.addEventListener('click',()=>{ b.classList.toggle('active'); lvlToggles[parseInt(b.dataset.level)]=b.classList.contains('active'); updateBtnStyle(b); updateHL(); });
1207
+ });
1208
+
1209
+ // ===== EDGE TOGGLES =====
1210
+ document.querySelectorAll('[data-edge]').forEach(b=>{
1211
+ b.addEventListener('click',()=>{
1212
+ if(b.dataset.edge==='all'){
1213
+ document.querySelectorAll('[data-edge]').forEach(x=>x.classList.remove('active'));
1214
+ b.classList.add('active');
1215
+ } else {
1216
+ document.querySelector('[data-edge="all"]').classList.remove('active');
1217
+ b.classList.toggle('active');
1218
+ if(!document.querySelectorAll('[data-edge].active').length) document.querySelector('[data-edge="all"]').classList.add('active');
1219
+ }
1220
+ updateHL();
1221
+ });
1222
+ });
1223
+
1224
+ // ===== CONTROLS TOGGLE =====
1225
+ const ctrlEl=document.getElementById('controls'), ctrlToggle=document.getElementById('controls-toggle');
1226
+ ctrlToggle.addEventListener('click',()=>{
1227
+ ctrlEl.classList.toggle('collapsed');
1228
+ ctrlToggle.textContent=ctrlEl.classList.contains('collapsed')?'\\u2699 Filters':'\\u2715 Close';
1229
+ });
1230
+
1231
+ // ===== GOLDEN ENERGY CORE (Jarvis consciousness center) =====
1232
+ const coreGeo = new THREE.IcosahedronGeometry(curSpread * 0.06, 3);
1233
+ const coreMat = new THREE.MeshBasicMaterial({
1234
+ color: 0xFFB800, transparent: true, opacity: 0.08,
1235
+ blending: THREE.AdditiveBlending, wireframe: true
1236
+ });
1237
+ const core = new THREE.Mesh(coreGeo, coreMat);
1238
+ scene.add(core);
1239
+ const core2Geo = new THREE.IcosahedronGeometry(curSpread * 0.025, 2);
1240
+ const core2Mat = new THREE.MeshBasicMaterial({
1241
+ color: 0xFFD080, transparent: true, opacity: 0.06,
1242
+ blending: THREE.AdditiveBlending
1243
+ });
1244
+ const core2 = new THREE.Mesh(core2Geo, core2Mat);
1245
+ scene.add(core2);
1246
+ // Warm golden point light at core center — subtle glow
1247
+ const coreLight = new THREE.PointLight(0xFFD080, 0.15, curSpread*0.3);
1248
+ scene.add(coreLight);
1249
+
1250
+ // ===== ORBIT PARTICLE STREAMS (animated orbital rings) =====
1251
+ const ORB_COUNT=200;
1252
+ const orbR=curSpread*1.6;
1253
+ // Per-particle radius for cloud-like band effect
1254
+ const orb1Rad=new Float32Array(ORB_COUNT), orb2Rad=new Float32Array(ORB_COUNT);
1255
+ // Orbit 1: green spectrum (Jarvis thoughts), horizontal cloud band
1256
+ const orb1Pos=new Float32Array(ORB_COUNT*3), orb1Col=new Float32Array(ORB_COUNT*3), orb1Sz=new Float32Array(ORB_COUNT);
1257
+ const orb1Phase=new Float32Array(ORB_COUNT);
1258
+ for(let i=0;i<ORB_COUNT;i++){
1259
+ orb1Phase[i]=(i/ORB_COUNT)*Math.PI*2+srand(i*53)*0.5;
1260
+ const isJ=i%12===0; // every 12th = Jarvis node (larger, brighter)
1261
+ orb1Sz[i]=isJ?9+srand(i*67)*4:4+srand(i*67)*5;
1262
+ orb1Rad[i]=orbR*(0.82+srand(i*113)*0.36);
1263
+ // Mixed green spectrum: emerald → cyan → jade
1264
+ const h=isJ?0.45+srand(i*137)*0.1:0.28+srand(i*137)*0.17;
1265
+ const tc=new THREE.Color().setHSL(h,0.75+srand(i*73)*0.25,isJ?0.55+srand(i*91)*0.15:0.42+srand(i*91)*0.18);
1266
+ orb1Col[i*3]=tc.r;orb1Col[i*3+1]=tc.g;orb1Col[i*3+2]=tc.b;
1267
+ }
1268
+ // Backup original sizes/colors for Jarvis orbit node overlay
1269
+ const orb1SzBase=new Float32Array(orb1Sz);
1270
+ const orb1ColBase=new Float32Array(orb1Col);
1271
+ const orb1Geo=new THREE.BufferGeometry();
1272
+ orb1Geo.setAttribute('position',new THREE.BufferAttribute(orb1Pos,3));
1273
+ orb1Geo.setAttribute('aColor',new THREE.BufferAttribute(orb1Col,3));
1274
+ orb1Geo.setAttribute('aSize',new THREE.BufferAttribute(orb1Sz,1));
1275
+ const orb1Pts=new THREE.Points(orb1Geo,new THREE.ShaderMaterial({
1276
+ vertexShader:\`attribute float aSize;attribute vec3 aColor;varying vec3 vC;void main(){vC=aColor;vec4 mv=modelViewMatrix*vec4(position,1.0);gl_PointSize=aSize*(800.0/-mv.z);gl_Position=projectionMatrix*mv;}\`,
1277
+ fragmentShader:\`varying vec3 vC;void main(){float d=length(gl_PointCoord-vec2(.5));if(d>.5)discard;float g=exp(-d*d*8.0);gl_FragColor=vec4(vC*1.8,g*0.85);}\`,
1278
+ transparent:true,depthWrite:false,blending:THREE.AdditiveBlending
1279
+ }));
1280
+ scene.add(orb1Pts);
1281
+ // Orbit 2: yellow (Jarvis proposals), tilted
1282
+ const orb2Pos=new Float32Array(ORB_COUNT*3), orb2Col=new Float32Array(ORB_COUNT*3), orb2Sz=new Float32Array(ORB_COUNT);
1283
+ const orb2Phase=new Float32Array(ORB_COUNT);
1284
+ const tiltX=Math.PI/2.5, tiltZ=Math.PI/6;
1285
+ const cosX=Math.cos(tiltX),sinX=Math.sin(tiltX),cosZ=Math.cos(tiltZ),sinZ=Math.sin(tiltZ);
1286
+ for(let i=0;i<ORB_COUNT;i++){
1287
+ orb2Phase[i]=(i/ORB_COUNT)*Math.PI*2+srand(i*59)*0.5;
1288
+ const isJ=i%12===0;
1289
+ orb2Sz[i]=isJ?8+srand(i*71)*3.5:3.5+srand(i*71)*5;
1290
+ orb2Rad[i]=orbR*(0.82+srand(i*119)*0.36);
1291
+ // Mixed gold spectrum: gold → amber → warm orange
1292
+ const h=isJ?0.12+srand(i*143)*0.06:0.08+srand(i*143)*0.12;
1293
+ const tc=new THREE.Color().setHSL(h,0.8+srand(i*79)*0.2,isJ?0.55+srand(i*97)*0.1:0.45+srand(i*97)*0.15);
1294
+ orb2Col[i*3]=tc.r;orb2Col[i*3+1]=tc.g;orb2Col[i*3+2]=tc.b;
1295
+ }
1296
+ const orb2SzBase=new Float32Array(orb2Sz);
1297
+ const orb2ColBase=new Float32Array(orb2Col);
1298
+ const orb2Geo=new THREE.BufferGeometry();
1299
+ orb2Geo.setAttribute('position',new THREE.BufferAttribute(orb2Pos,3));
1300
+ orb2Geo.setAttribute('aColor',new THREE.BufferAttribute(orb2Col,3));
1301
+ orb2Geo.setAttribute('aSize',new THREE.BufferAttribute(orb2Sz,1));
1302
+ const orb2Pts=new THREE.Points(orb2Geo,orb1Pts.material);
1303
+ scene.add(orb2Pts);
1304
+ // Orbit center offset (updated by buildGeometry)
1305
+ let orbCx=0,orbCy=0,orbCz=0;
1306
+
1307
+ // ===== ORBIT TRAILS (fading particle tails behind orbit particles) =====
1308
+ const TRAIL_LEN=6;
1309
+ const trail1Pos=new Float32Array(ORB_COUNT*TRAIL_LEN*3);
1310
+ const trail1Sz=new Float32Array(ORB_COUNT*TRAIL_LEN);
1311
+ const trail1Col=new Float32Array(ORB_COUNT*TRAIL_LEN*3);
1312
+ for(let i=0;i<ORB_COUNT;i++){
1313
+ for(let j=0;j<TRAIL_LEN;j++){
1314
+ const idx=i*TRAIL_LEN+j;
1315
+ trail1Sz[idx]=Math.max(1,orb1Sz[i]*(1-j/TRAIL_LEN)*0.6);
1316
+ trail1Col[idx*3]=orb1Col[i*3];trail1Col[idx*3+1]=orb1Col[i*3+1];trail1Col[idx*3+2]=orb1Col[i*3+2];
1317
+ }
1318
+ }
1319
+ const trail1Geo=new THREE.BufferGeometry();
1320
+ trail1Geo.setAttribute('position',new THREE.BufferAttribute(trail1Pos,3));
1321
+ trail1Geo.setAttribute('aColor',new THREE.BufferAttribute(trail1Col,3));
1322
+ trail1Geo.setAttribute('aSize',new THREE.BufferAttribute(trail1Sz,1));
1323
+ const trail1Pts=new THREE.Points(trail1Geo,new THREE.ShaderMaterial({
1324
+ vertexShader:\`attribute float aSize;attribute vec3 aColor;varying vec3 vC;void main(){vC=aColor;vec4 mv=modelViewMatrix*vec4(position,1.0);gl_PointSize=aSize*(800.0/-mv.z);gl_Position=projectionMatrix*mv;}\`,
1325
+ fragmentShader:\`varying vec3 vC;void main(){float d=length(gl_PointCoord-vec2(.5));if(d>.5)discard;float g=exp(-d*d*8.0);gl_FragColor=vec4(vC*1.4,g*0.45);}\`,
1326
+ transparent:true,depthWrite:false,blending:THREE.AdditiveBlending
1327
+ }));
1328
+ scene.add(trail1Pts);
1329
+
1330
+ const trail2Pos=new Float32Array(ORB_COUNT*TRAIL_LEN*3);
1331
+ const trail2Sz=new Float32Array(ORB_COUNT*TRAIL_LEN);
1332
+ const trail2Col=new Float32Array(ORB_COUNT*TRAIL_LEN*3);
1333
+ for(let i=0;i<ORB_COUNT;i++){
1334
+ for(let j=0;j<TRAIL_LEN;j++){
1335
+ const idx=i*TRAIL_LEN+j;
1336
+ trail2Sz[idx]=Math.max(1,orb2Sz[i]*(1-j/TRAIL_LEN)*0.6);
1337
+ trail2Col[idx*3]=orb2Col[i*3];trail2Col[idx*3+1]=orb2Col[i*3+1];trail2Col[idx*3+2]=orb2Col[i*3+2];
1338
+ }
1339
+ }
1340
+ const trail2Geo=new THREE.BufferGeometry();
1341
+ trail2Geo.setAttribute('position',new THREE.BufferAttribute(trail2Pos,3));
1342
+ trail2Geo.setAttribute('aColor',new THREE.BufferAttribute(trail2Col,3));
1343
+ trail2Geo.setAttribute('aSize',new THREE.BufferAttribute(trail2Sz,1));
1344
+ const trail2Pts=new THREE.Points(trail2Geo,trail1Pts.material);
1345
+ scene.add(trail2Pts);
1346
+
1347
+ // ===== ORBIT 3: cyan-violet spectrum, polar ring (cross-cutting path) =====
1348
+ const ORB3_COUNT=150;
1349
+ const orb3Pos=new Float32Array(ORB3_COUNT*3), orb3Col=new Float32Array(ORB3_COUNT*3), orb3Sz=new Float32Array(ORB3_COUNT);
1350
+ const orb3Phase=new Float32Array(ORB3_COUNT), orb3Rad=new Float32Array(ORB3_COUNT);
1351
+ const tilt3Y=Math.PI/3.2, tilt3X=Math.PI/2.1;
1352
+ const cos3Y=Math.cos(tilt3Y),sin3Y=Math.sin(tilt3Y),cos3X=Math.cos(tilt3X),sin3X=Math.sin(tilt3X);
1353
+ for(let i=0;i<ORB3_COUNT;i++){
1354
+ orb3Phase[i]=(i/ORB3_COUNT)*Math.PI*2+srand(i*61)*0.5;
1355
+ const isJ=i%15===0;
1356
+ orb3Sz[i]=isJ?7+srand(i*83)*3:3+srand(i*83)*4;
1357
+ orb3Rad[i]=orbR*(0.85+srand(i*127)*0.3);
1358
+ // Cyan-violet spectrum
1359
+ const h=isJ?0.7+srand(i*151)*0.1:0.5+srand(i*151)*0.25;
1360
+ const tc=new THREE.Color().setHSL(h,0.7+srand(i*89)*0.3,isJ?0.55+srand(i*103)*0.1:0.4+srand(i*103)*0.2);
1361
+ orb3Col[i*3]=tc.r;orb3Col[i*3+1]=tc.g;orb3Col[i*3+2]=tc.b;
1362
+ }
1363
+ const orb3Geo=new THREE.BufferGeometry();
1364
+ orb3Geo.setAttribute('position',new THREE.BufferAttribute(orb3Pos,3));
1365
+ orb3Geo.setAttribute('aColor',new THREE.BufferAttribute(orb3Col,3));
1366
+ orb3Geo.setAttribute('aSize',new THREE.BufferAttribute(orb3Sz,1));
1367
+ const orb3Pts=new THREE.Points(orb3Geo,orb1Pts.material);
1368
+ scene.add(orb3Pts);
1369
+ // Orbit 3 trails
1370
+ const trail3Pos=new Float32Array(ORB3_COUNT*TRAIL_LEN*3);
1371
+ const trail3Sz=new Float32Array(ORB3_COUNT*TRAIL_LEN);
1372
+ const trail3Col=new Float32Array(ORB3_COUNT*TRAIL_LEN*3);
1373
+ for(let i=0;i<ORB3_COUNT;i++){
1374
+ for(let j=0;j<TRAIL_LEN;j++){
1375
+ const idx=i*TRAIL_LEN+j;
1376
+ trail3Sz[idx]=Math.max(1,orb3Sz[i]*(1-j/TRAIL_LEN)*0.6);
1377
+ trail3Col[idx*3]=orb3Col[i*3];trail3Col[idx*3+1]=orb3Col[i*3+1];trail3Col[idx*3+2]=orb3Col[i*3+2];
1378
+ }
1379
+ }
1380
+ const trail3Geo=new THREE.BufferGeometry();
1381
+ trail3Geo.setAttribute('position',new THREE.BufferAttribute(trail3Pos,3));
1382
+ trail3Geo.setAttribute('aColor',new THREE.BufferAttribute(trail3Col,3));
1383
+ trail3Geo.setAttribute('aSize',new THREE.BufferAttribute(trail3Sz,1));
1384
+ const trail3Pts=new THREE.Points(trail3Geo,trail1Pts.material);
1385
+ scene.add(trail3Pts);
1386
+
1387
+ // ===== JARVIS NEURONS (shoot from orbits to core) =====
1388
+ const JARVIS_NEURON_COUNT=30;
1389
+ const jNeurons=[];
1390
+ let jOrbitSpeed=1.0; // Dynamic: faster when thinking
1391
+ function fireNeuron(color,trigger){
1392
+ if(jNeurons.length>=JARVIS_NEURON_COUNT) return;
1393
+ const orbitAngle=Math.random()*Math.PI*2;
1394
+ const orbChoice=Math.random();
1395
+ let sx,sy,sz;
1396
+ if(orbChoice<0.33){
1397
+ sx=orbCx+Math.cos(orbitAngle)*orbR;sy=orbCy;sz=orbCz+Math.sin(orbitAngle)*orbR;
1398
+ } else if(orbChoice<0.66){
1399
+ const lx=Math.cos(orbitAngle)*orbR,ly=0,lz=Math.sin(orbitAngle)*orbR;
1400
+ const ry=ly*cosX-lz*sinX,rz=ly*sinX+lz*cosX;
1401
+ const fx=lx*cosZ-ry*sinZ,fy=lx*sinZ+ry*cosZ;
1402
+ sx=orbCx+fx;sy=orbCy+fy;sz=orbCz+rz;
1403
+ } else {
1404
+ // Orbit 3: polar ring
1405
+ const lx=Math.cos(orbitAngle)*orbR,ly=0,lz=Math.sin(orbitAngle)*orbR;
1406
+ const ry3=ly*cos3X-lz*sin3X,rz3=ly*sin3X+lz*cos3X;
1407
+ const fx3=lx*cos3Y-ry3*sin3Y,fy3=lx*sin3Y+ry3*cos3Y;
1408
+ sx=orbCx+fx3;sy=orbCy+fy3;sz=orbCz+rz3;
1409
+ }
1410
+ const c=new THREE.Color(color||0x00FF66);
1411
+ const speed=0.5+Math.random()*1.0;
1412
+ const geo=new THREE.BufferGeometry();
1413
+ const trailLen=8;
1414
+ const positions=new Float32Array(trailLen*3);
1415
+ for(let j=0;j<trailLen;j++){positions[j*3]=sx;positions[j*3+1]=sy;positions[j*3+2]=sz;}
1416
+ geo.setAttribute('position',new THREE.BufferAttribute(positions,3));
1417
+ const mat=new THREE.LineBasicMaterial({color:c,transparent:true,opacity:0.4,blending:THREE.AdditiveBlending});
1418
+ const line=new THREE.Line(geo,mat);
1419
+ scene.add(line);
1420
+ jNeurons.push({x:sx,y:sy,z:sz,speed,color:c,line,geo,life:0,maxLife:3.0,trail:Array.from({length:trailLen},()=>({x:sx,y:sy,z:sz}))});
1421
+ }
1422
+ function updateNeurons(dt){
1423
+ for(let i=jNeurons.length-1;i>=0;i--){
1424
+ const n=jNeurons[i];
1425
+ n.life+=dt;
1426
+ const dx=orbCx-n.x,dy=orbCy-n.y,dz=orbCz-n.z;
1427
+ const dist=Math.sqrt(dx*dx+dy*dy+dz*dz);
1428
+ if(dist<5||n.life>n.maxLife){
1429
+ scene.remove(n.line);n.geo.dispose();n.line.material.dispose();
1430
+ jNeurons.splice(i,1);continue;
1431
+ }
1432
+ const s=n.speed*dt*60;
1433
+ n.x+=dx/dist*s;n.y+=dy/dist*s;n.z+=dz/dist*s;
1434
+ n.trail.pop();n.trail.unshift({x:n.x,y:n.y,z:n.z});
1435
+ const pos=n.geo.attributes.position;
1436
+ for(let j=0;j<n.trail.length;j++){
1437
+ pos.array[j*3]=n.trail[j].x;pos.array[j*3+1]=n.trail[j].y;pos.array[j*3+2]=n.trail[j].z;
1438
+ }
1439
+ pos.needsUpdate=true;
1440
+ n.line.material.opacity=0.4*(1-n.life/n.maxLife);
1441
+ }
1442
+ }
1443
+
1444
+ // ===== JARVIS CONSCIOUSNESS STATE =====
1445
+ let jarvisThinkingPhase='idle';
1446
+ let jarvisThinkingLabel=null;
1447
+ function updateJarvisThinking(phase){
1448
+ jarvisThinkingPhase=phase;
1449
+ jOrbitSpeed=phase==='quick'?1.5:phase==='medium'?2.5:phase==='deep'?4.0:1.0;
1450
+ if(phase!=='idle'){
1451
+ fireNeuron(phase==='deep'?0xFF00FF:0x00FF66,phase);
1452
+ fireNeuron(phase==='deep'?0xFFDD00:0x00FF66,phase);
1453
+ }
1454
+ }
1455
+
1456
+ // ===== JARVIS TASK/PROPOSAL ORBIT NODES =====
1457
+ // Green orbit → active tasks (pending/in_progress)
1458
+ // Gold orbit → proposals (pending approval)
1459
+ let jarvisActiveTasks=[];
1460
+ let jarvisActiveProposals=[];
1461
+ const TASK_PARTICLE_SPACING=25; // every Nth orbit1 particle becomes a task node
1462
+ const PROPOSAL_PARTICLE_SPACING=25; // every Nth orbit2 particle becomes a proposal node
1463
+
1464
+ function updateJarvisTask(task){
1465
+ const idx=jarvisActiveTasks.findIndex(t=>t.id===task.id);
1466
+ if(task.status==='completed'||task.status==='cancelled'){
1467
+ if(idx>=0){
1468
+ fireNeuron(0x00FF66,'task_complete');
1469
+ jarvisActiveTasks.splice(idx,1);
1470
+ }
1471
+ return;
1472
+ }
1473
+ if(idx>=0) jarvisActiveTasks[idx]=task;
1474
+ else jarvisActiveTasks.push(task);
1475
+ }
1476
+
1477
+ function updateJarvisProposal(proposal){
1478
+ const idx=jarvisActiveProposals.findIndex(p=>p.id===proposal.id);
1479
+ if(proposal.status==='approved'){
1480
+ if(idx>=0){
1481
+ fireNeuron(0xFFDD00,'proposal_approved');
1482
+ jarvisActiveProposals.splice(idx,1);
1483
+ }
1484
+ return;
1485
+ }
1486
+ if(proposal.status==='denied'){
1487
+ if(idx>=0){
1488
+ fireNeuron(0xFF4444,'proposal_denied');
1489
+ jarvisActiveProposals.splice(idx,1);
1490
+ }
1491
+ return;
1492
+ }
1493
+ if(idx>=0) jarvisActiveProposals[idx]=proposal;
1494
+ else jarvisActiveProposals.push(proposal);
1495
+ }
1496
+
1497
+ // Apply task/proposal sizes to orbit particles each frame
1498
+ function applyJarvisOrbitNodes(){
1499
+ if(jarvisActiveTasks.length===0&&jarvisActiveProposals.length===0) return;
1500
+ // Green orbit: enlarge particles that represent active tasks
1501
+ const o1SzAttr=orb1Geo.attributes.aSize;
1502
+ if(o1SzAttr){
1503
+ const arr=o1SzAttr.array;
1504
+ // Reset all to base size from backup
1505
+ for(let i=0;i<ORB_COUNT;i++) arr[i]=orb1SzBase[i];
1506
+ // Assign tasks to evenly-spaced particle slots
1507
+ const taskCount=Math.min(jarvisActiveTasks.length,Math.floor(ORB_COUNT/TASK_PARTICLE_SPACING));
1508
+ for(let ti=0;ti<taskCount;ti++){
1509
+ const pi=ti*TASK_PARTICLE_SPACING;
1510
+ const task=jarvisActiveTasks[ti];
1511
+ const isActive=task.status==='in_progress';
1512
+ arr[pi]=isActive?22:16; // much larger than normal (4-8)
1513
+ }
1514
+ o1SzAttr.needsUpdate=true;
1515
+ }
1516
+ // Also brighten task particle colors
1517
+ const o1ColAttr=orb1Geo.attributes.aColor;
1518
+ if(o1ColAttr){
1519
+ const arr=o1ColAttr.array;
1520
+ // Reset from backup
1521
+ for(let i=0;i<ORB_COUNT*3;i++) arr[i]=orb1ColBase[i];
1522
+ const taskCount=Math.min(jarvisActiveTasks.length,Math.floor(ORB_COUNT/TASK_PARTICLE_SPACING));
1523
+ for(let ti=0;ti<taskCount;ti++){
1524
+ const pi=ti*TASK_PARTICLE_SPACING;
1525
+ const task=jarvisActiveTasks[ti];
1526
+ const isActive=task.status==='in_progress';
1527
+ // Bright green for active, softer for pending
1528
+ arr[pi*3]=isActive?0.2:0.1;
1529
+ arr[pi*3+1]=isActive?1.0:0.7;
1530
+ arr[pi*3+2]=isActive?0.5:0.3;
1531
+ }
1532
+ o1ColAttr.needsUpdate=true;
1533
+ }
1534
+ // Gold orbit: enlarge particles for proposals
1535
+ const o2SzAttr=orb2Geo.attributes.aSize;
1536
+ if(o2SzAttr){
1537
+ const arr=o2SzAttr.array;
1538
+ for(let i=0;i<ORB_COUNT;i++) arr[i]=orb2SzBase[i];
1539
+ const propCount=Math.min(jarvisActiveProposals.length,Math.floor(ORB_COUNT/PROPOSAL_PARTICLE_SPACING));
1540
+ for(let pi=0;pi<propCount;pi++){
1541
+ const idx=pi*PROPOSAL_PARTICLE_SPACING;
1542
+ arr[idx]=18; // larger for proposals
1543
+ }
1544
+ o2SzAttr.needsUpdate=true;
1545
+ }
1546
+ const o2ColAttr=orb2Geo.attributes.aColor;
1547
+ if(o2ColAttr){
1548
+ const arr=o2ColAttr.array;
1549
+ for(let i=0;i<ORB_COUNT*3;i++) arr[i]=orb2ColBase[i];
1550
+ const propCount=Math.min(jarvisActiveProposals.length,Math.floor(ORB_COUNT/PROPOSAL_PARTICLE_SPACING));
1551
+ for(let pi=0;pi<propCount;pi++){
1552
+ const idx=pi*PROPOSAL_PARTICLE_SPACING;
1553
+ // Bright gold for proposals
1554
+ arr[idx*3]=1.0;arr[idx*3+1]=0.85;arr[idx*3+2]=0.2;
1555
+ }
1556
+ o2ColAttr.needsUpdate=true;
1557
+ }
1558
+ }
1559
+
1560
+ // ===== ANIMATE (cinematic: bloom + core pulse + edge breathing) =====
1561
+ let fpsF=0, lastFT=performance.now();
1562
+ const clock=new THREE.Clock();
1563
+
1564
+ function animate(){
1565
+ requestAnimationFrame(animate);
1566
+ const dt=clock.getDelta();
1567
+
1568
+ if(camTw){
1569
+ camTw.p=Math.min(camTw.p+dt*1.8,1);
1570
+ const e=1-Math.pow(1-camTw.p,3);
1571
+ cam.position.lerpVectors(camTw.sP,camTw.tP,e);
1572
+ ctrl.target.lerpVectors(camTw.sL,camTw.tL,e);
1573
+ if(camTw.p>=1)camTw=null;
1574
+ }
1575
+
1576
+ // Energy core pulse + color cycling
1577
+ const t=performance.now();
1578
+ core.rotation.y += dt * 0.12;
1579
+ core.rotation.x += dt * 0.06;
1580
+ const corePulse=1 + Math.sin(t * 0.001) * 0.08;
1581
+ core.scale.setScalar(corePulse);
1582
+ core2.scale.setScalar(1 + Math.sin(t * 0.0015) * 0.1);
1583
+ // Core gold/orange spectrum pulse (always warm golden)
1584
+ const coreHue=0.07+Math.sin(t*0.0003)*0.04; // hue 0.03-0.11 (gold–orange)
1585
+ const _coreC=new THREE.Color().setHSL(coreHue,0.9,0.55);
1586
+ coreMat.color.copy(_coreC);
1587
+ core2Mat.color.copy(new THREE.Color().setHSL(coreHue+0.02,0.85,0.6));
1588
+ coreLight.color.copy(_coreC);
1589
+ coreMat.opacity=0.06+Math.sin(t*0.002)*0.04;
1590
+ core2Mat.opacity=0.05+Math.sin(t*0.0025)*0.03;
1591
+
1592
+ // Edge breathing
1593
+ eMat.uniforms.uBreath.value = 1.0 + Math.sin(t * 0.0008) * 0.15;
1594
+
1595
+ // Core light position
1596
+ coreLight.position.set(orbCx,orbCy,orbCz);
1597
+
1598
+ // Update Jarvis neurons + orbit task/proposal nodes
1599
+ updateNeurons(dt);
1600
+ applyJarvisOrbitNodes();
1601
+
1602
+ // Orbit particle streams — cloud-like bands with per-particle radius
1603
+ const oSp=t*0.0003*jOrbitSpeed;
1604
+ const o1=orb1Geo.attributes.position;
1605
+ for(let i=0;i<ORB_COUNT;i++){
1606
+ const a=orb1Phase[i]+oSp;
1607
+ const r=orb1Rad[i];
1608
+ o1.array[i*3]=orbCx+Math.cos(a)*r;
1609
+ o1.array[i*3+1]=orbCy+(srand(i*89)-0.5)*16+Math.sin(t*0.0008+i*0.3)*4;
1610
+ o1.array[i*3+2]=orbCz+Math.sin(a)*r;
1611
+ }
1612
+ o1.needsUpdate=true;
1613
+ const o2=orb2Geo.attributes.position;
1614
+ const oSp2=t*0.00025*jOrbitSpeed;
1615
+ for(let i=0;i<ORB_COUNT;i++){
1616
+ const a=orb2Phase[i]-oSp2;
1617
+ const r=orb2Rad[i];
1618
+ const lx=Math.cos(a)*r, ly=0, lz=Math.sin(a)*r;
1619
+ const ry=ly*cosX-lz*sinX, rz=ly*sinX+lz*cosX;
1620
+ const fx=lx*cosZ-ry*sinZ, fy=lx*sinZ+ry*cosZ;
1621
+ o2.array[i*3]=orbCx+fx;
1622
+ o2.array[i*3+1]=orbCy+fy+(srand(i*97)-0.5)*14+Math.sin(t*0.0009+i*0.25)*3;
1623
+ o2.array[i*3+2]=orbCz+rz;
1624
+ }
1625
+ o2.needsUpdate=true;
1626
+ // Orbit 3 animation (polar cross-ring)
1627
+ const o3=orb3Geo.attributes.position;
1628
+ const oSp3=t*0.00022*jOrbitSpeed;
1629
+ for(let i=0;i<ORB3_COUNT;i++){
1630
+ const a=orb3Phase[i]+oSp3;
1631
+ const r=orb3Rad[i];
1632
+ const lx=Math.cos(a)*r, ly=0, lz=Math.sin(a)*r;
1633
+ const ry3=ly*cos3X-lz*sin3X, rz3=ly*sin3X+lz*cos3X;
1634
+ const fx3=lx*cos3Y-ry3*sin3Y, fy3=lx*sin3Y+ry3*cos3Y;
1635
+ o3.array[i*3]=orbCx+fx3;
1636
+ o3.array[i*3+1]=orbCy+fy3+(srand(i*101)-0.5)*12+Math.sin(t*0.001+i*0.2)*3;
1637
+ o3.array[i*3+2]=orbCz+rz3;
1638
+ }
1639
+ o3.needsUpdate=true;
1640
+
1641
+ // Update orbit trails — shift positions backward, insert current at front
1642
+ const t1p=trail1Geo.attributes.position;
1643
+ for(let i=0;i<ORB_COUNT;i++){
1644
+ const base=i*TRAIL_LEN;
1645
+ for(let j=TRAIL_LEN-1;j>0;j--){
1646
+ const dst=(base+j)*3, src=(base+j-1)*3;
1647
+ t1p.array[dst]=t1p.array[src]; t1p.array[dst+1]=t1p.array[src+1]; t1p.array[dst+2]=t1p.array[src+2];
1648
+ }
1649
+ const f=base*3;
1650
+ t1p.array[f]=o1.array[i*3]; t1p.array[f+1]=o1.array[i*3+1]; t1p.array[f+2]=o1.array[i*3+2];
1651
+ }
1652
+ t1p.needsUpdate=true;
1653
+
1654
+ const t2p=trail2Geo.attributes.position;
1655
+ for(let i=0;i<ORB_COUNT;i++){
1656
+ const base=i*TRAIL_LEN;
1657
+ for(let j=TRAIL_LEN-1;j>0;j--){
1658
+ const dst=(base+j)*3, src=(base+j-1)*3;
1659
+ t2p.array[dst]=t2p.array[src]; t2p.array[dst+1]=t2p.array[src+1]; t2p.array[dst+2]=t2p.array[src+2];
1660
+ }
1661
+ const f=base*3;
1662
+ t2p.array[f]=o2.array[i*3]; t2p.array[f+1]=o2.array[i*3+1]; t2p.array[f+2]=o2.array[i*3+2];
1663
+ }
1664
+ t2p.needsUpdate=true;
1665
+
1666
+ // Trail 3
1667
+ const t3p=trail3Geo.attributes.position;
1668
+ for(let i=0;i<ORB3_COUNT;i++){
1669
+ const base=i*TRAIL_LEN;
1670
+ for(let j=TRAIL_LEN-1;j>0;j--){
1671
+ const dst=(base+j)*3, src=(base+j-1)*3;
1672
+ t3p.array[dst]=t3p.array[src]; t3p.array[dst+1]=t3p.array[src+1]; t3p.array[dst+2]=t3p.array[src+2];
1673
+ }
1674
+ const f=base*3;
1675
+ t3p.array[f]=o3.array[i*3]; t3p.array[f+1]=o3.array[i*3+1]; t3p.array[f+2]=o3.array[i*3+2];
1676
+ }
1677
+ t3p.needsUpdate=true;
1678
+
1679
+ updateSignals(dt);
1680
+ ctrl.update();
1681
+ composer.render();
1682
+
1683
+ fpsF++;
1684
+ const now=performance.now();
1685
+ if(now-lastFT>1000){ document.getElementById('fps-counter').textContent=fpsF; fpsF=0; lastFT=now; }
1686
+ }
1687
+
1688
+ // ===== RESIZE =====
1689
+ addEventListener('resize',()=>{ const w=innerWidth,h=innerHeight,d=Math.min(window.devicePixelRatio,2); cam.aspect=w/h; cam.updateProjectionMatrix(); R.setSize(w,h); composer.setSize(Math.floor(w*d),Math.floor(h*d)); });
1690
+
1691
+ // ===== STATIC MODE DETECTION =====
1692
+ // Hide interactive controls when served as static file (no CLI WebSocket available)
1693
+ const isStatic=window!==window.top||!location.host.match(/^(127\\.0\\.0\\.1|localhost)(:\\d+)?$/);
1694
+ if(isStatic){
1695
+ const vp=document.getElementById('voice-panel');if(vp)vp.style.display='none';
1696
+ const ft=document.getElementById('findings-toggle');if(ft)ft.style.display='none';
1697
+ const mt=document.getElementById('models-toggle');if(mt)mt.style.display='none';
1698
+ }
1699
+
1700
+ // ===== WEBSOCKET =====
1701
+ let ws=null;
1702
+ (function connectWS(){
1703
+ const proto=location.protocol==='https:'?'wss:':'ws:';
1704
+ function connect(){
1705
+ try{ws=new WebSocket(proto+'//'+location.host)}catch{return}
1706
+ ws.onmessage=(ev)=>{
1707
+ try{
1708
+ const m=JSON.parse(ev.data);
1709
+ if(m.type==='full_sync'&&m.data){
1710
+ const newIds=m.data.nodes.map(n=>n.id).sort().join(',');
1711
+ if(newIds!==lastNodeIds){ lastNodeIds=newIds; BRAIN_DATA=m.data; buildScene(); }
1712
+ }
1713
+ if(m.type==='web_knowledge') showWKPopup(m.topic,m.summary,m.source);
1714
+ if(m.type==='agent_finding') addFinding(m.sessionName,m.finding,m.severity,m.file);
1715
+ if(m.type==='scope_changed') updateScopeUI(m.scope);
1716
+ if(m.type==='ollama_starting'){
1717
+ oStatus.textContent='Ollama starting...';oStatus.style.color='#ffaa00';
1718
+ setTimeout(()=>refreshModels(),2000);
1719
+ setTimeout(()=>refreshModels(),5000);
1720
+ }
1721
+ // Jarvis AGI events
1722
+ if(m.type==='thinking_update') updateJarvisThinking(m.phase);
1723
+ if(m.type==='consciousness_event'){ fireNeuron(0xFF00FF,'consciousness'); addFinding('Jarvis',m.content,'info',''); }
1724
+ if(m.type==='jarvis_learning'){ fireNeuron(0xFFB800,'learning'); }
1725
+ if(m.type==='neuron_fired') fireNeuron(parseInt(m.color)||0x00FF66,m.trigger);
1726
+ if(m.type==='proposal_created'){ fireNeuron(0xFFDD00,'proposal'); addFinding('Jarvis','Proposal: '+(m.proposal?.title||''),'info',''); }
1727
+ if(m.type==='identity_changed') fireNeuron(m.newValue>m.oldValue?0x00FF66:0xFF8800,'identity');
1728
+ if(m.type==='autonomy_changed') addFinding('Jarvis','Autonomy: L'+m.oldLevel+' \\u2192 L'+m.newLevel+' ('+m.reason+')','info','');
1729
+ if(m.type==='trigger_fired'){ fireNeuron(0x00FF66,'trigger'); addFinding('Jarvis','Trigger: '+m.details,'info',''); }
1730
+ if(m.type==='worker_started') addFinding('Jarvis','Worker started: '+(m.worker?.taskTitle||''),'info','');
1731
+ if(m.type==='worker_completed') addFinding('Jarvis','Worker done: '+(m.worker?.taskTitle||''),'info','');
1732
+ if(m.type==='tts_audio'&&m.audioBase64){ try{const a=new Audio('data:audio/mpeg;base64,'+m.audioBase64);a.play();}catch{} }
1733
+ // Brain Management
1734
+ if(m.type==='brain_list') renderBrainList(m.brains,m.limits);
1735
+ if(m.type==='brain_renamed') updateBrainName(m.brainId,m.newName);
1736
+ if(m.type==='brain_switched') selectBrainCard(m.brainId);
1737
+ if(m.type==='brain_created') requestBrainList();
1738
+ if(m.type==='brain_limit_reached') showLimitToast(m.limitType,m.current,m.max);
1739
+ // Jarvis task updates for plan view + orbit nodes
1740
+ if(m.type==='jarvis_task_created'||m.type==='jarvis_task_updated'){ updatePlanView(m.task); updateJarvisTask(m.task); }
1741
+ // Jarvis proposal updates for orbit nodes
1742
+ if(m.type==='proposal_created'||m.type==='proposal_updated'){ if(m.proposal) updateJarvisProposal(m.proposal); }
1743
+ if(m.type==='model_activated'){
1744
+ document.querySelectorAll('[data-activate]').forEach(b=>{b.disabled=false;b.textContent='\\u26A1 Activate';});
1745
+ const n=document.createElement('div');
1746
+ n.style.cssText='position:fixed;top:60px;left:50%;transform:translateX(-50%);background:rgba(0,255,100,0.15);border:1px solid rgba(0,255,100,0.3);color:#00ff66;padding:8px 20px;border-radius:8px;font-size:12px;z-index:999;backdrop-filter:blur(10px);';
1747
+ n.textContent='\\u26A1 Model activated: '+m.model;
1748
+ document.body.appendChild(n); setTimeout(()=>n.remove(),3000); refreshModels();
1749
+ }
1750
+ }catch{}
1751
+ };
1752
+ ws.onclose=()=>setTimeout(connect,3000);
1753
+ ws.onerror=()=>ws.close();
1754
+ }
1755
+ connect();
1756
+ })();
1757
+
1758
+ // ===== WEB KNOWLEDGE POPUPS =====
1759
+ function showWKPopup(topic,summary,source){
1760
+ const ct=document.getElementById('web-knowledge-container');
1761
+ const p=document.createElement('div'); p.className='web-knowledge-popup';
1762
+ let dU=source; try{const u=new URL(source);dU=u.hostname+u.pathname.slice(0,30);}catch{}
1763
+ p.innerHTML='<div class="wk-header"><span class="wk-icon">\\u{1F310}</span><span class="wk-title">Web Knowledge</span></div><div class="wk-topic">'+esc(topic)+'</div><div class="wk-summary">'+esc(summary)+'</div><div class="wk-source">'+esc(dU)+'</div><div class="wk-progress"><div class="wk-progress-bar"></div></div>';
1764
+ ct.appendChild(p);
1765
+ setTimeout(()=>{p.classList.add('removing');setTimeout(()=>p.remove(),500);},6000);
1766
+ while(ct.children.length>3) ct.firstChild.remove();
1767
+ }
1768
+
1769
+ // ===== SCOPE SWITCHER =====
1770
+ let curScope='${data.meta.brainScope === 'project' ? 'project' : 'global'}';
1771
+ document.querySelectorAll('#scope-switcher .scope-btn').forEach(b=>{
1772
+ b.addEventListener('click',()=>{
1773
+ const ns=b.dataset.scope; if(ns===curScope)return;
1774
+ const proto=location.protocol==='https:'?'wss:':'ws:';
1775
+ const sw=new WebSocket(proto+'//'+location.host);
1776
+ sw.onopen=()=>{sw.send(JSON.stringify({type:'scope_switch',scope:ns}));sw.close();};
1777
+ updateScopeUI(ns);
1778
+ });
1779
+ });
1780
+ function updateScopeUI(s){ curScope=s; document.querySelectorAll('#scope-switcher .scope-btn').forEach(b=>b.classList.toggle('active',b.dataset.scope===s)); }
1781
+
1782
+ // ===== FINDINGS =====
1783
+ let fData=[];
1784
+ const fPanel=document.getElementById('findings-panel'), fList=document.getElementById('findings-list');
1785
+ const fCount=document.getElementById('findings-count'), fToggle=document.getElementById('findings-toggle'), fBadge=document.getElementById('findings-badge');
1786
+ fToggle.addEventListener('click',()=>fPanel.classList.toggle('open'));
1787
+ document.getElementById('findings-close').addEventListener('click',()=>fPanel.classList.remove('open'));
1788
+ function addFinding(sn,f,sev,file){
1789
+ fData.push({sn,f,sev,file,t:Date.now()});
1790
+ fBadge.style.display='inline'; fBadge.textContent=fData.length;
1791
+ fCount.textContent=fData.length+' finding(s)';
1792
+ fList.innerHTML='';
1793
+ for(const d of[...fData].reverse()){
1794
+ const it=document.createElement('div'); it.className='finding-item';
1795
+ it.innerHTML='<span class="f-severity '+d.sev+'">'+d.sev+'</span> <div class="f-text">'+esc(d.f)+'</div>'+(d.file?'<div class="f-file">'+esc(d.file)+'</div>':'')+'<div class="f-file">'+esc(d.sn)+'</div>';
1796
+ fList.appendChild(it);
1797
+ }
1798
+ if(fData.length===1) fPanel.classList.add('open');
1799
+ }
1800
+
1801
+ // ===== MODEL MANAGEMENT =====
1802
+ const RECO=[
1803
+ {name:'qwen3-coder:30b',size:'~18 GB',desc:'Best coding model for 32GB VRAM',vram:18},
1804
+ {name:'qwen2.5-coder:32b',size:'~22 GB',desc:'Battle-tested coding champion',vram:22},
1805
+ {name:'qwen2.5-coder:14b',size:'~10 GB',desc:'Great coding, lower VRAM',vram:10},
1806
+ {name:'deepseek-r1:32b',size:'~22 GB',desc:'Strong reasoning + coding',vram:22},
1807
+ {name:'qwen2.5-coder:7b',size:'~5 GB',desc:'Lightweight coder',vram:5},
1808
+ ];
1809
+ const mPanel=document.getElementById('models-panel'), mToggle=document.getElementById('models-toggle'), mClose=document.getElementById('models-close');
1810
+ const oStatus=document.getElementById('ollama-status'), oDot=document.getElementById('ollama-dot');
1811
+ let curVram=32, instNames=new Set(), runNames=new Set(), oOnline=false;
1812
+
1813
+ mToggle.addEventListener('click',()=>{
1814
+ if(!oOnline&&ws&&ws.readyState===WebSocket.OPEN){
1815
+ ws.send(JSON.stringify({type:'start_ollama'}));
1816
+ oStatus.textContent='Starting Ollama...';oStatus.style.color='#ffaa00';
1817
+ oDot.className='status-dot offline';
1818
+ setTimeout(()=>refreshModels(),3000);
1819
+ }
1820
+ mPanel.classList.toggle('open');if(mPanel.classList.contains('open'))refreshModels();
1821
+ });
1822
+ mClose.addEventListener('click',()=>mPanel.classList.remove('open'));
1823
+ document.querySelectorAll('#gpu-filter .gpu-btn').forEach(b=>{
1824
+ b.addEventListener('click',()=>{document.querySelectorAll('#gpu-filter .gpu-btn').forEach(x=>x.classList.remove('active'));b.classList.add('active');curVram=parseInt(b.dataset.vram);renderReco();});
1825
+ });
1826
+
1827
+ async function checkOllama(){
1828
+ try{const r=await fetch('/api/ollama/status');const d=await r.json();if(d.version){oOnline=true;oStatus.textContent='Ollama v'+d.version+' \\u2014 running';oStatus.style.color='#00ff88';oDot.className='status-dot online';mToggle.classList.add('online');return true;}}catch{}
1829
+ oOnline=false;oStatus.textContent='Ollama not running \\u2014 click to start';oStatus.style.color='#ff4444';oDot.className='status-dot offline';mToggle.classList.remove('online');return false;
1830
+ }
1831
+ async function fetchInst(){try{const r=await fetch('/api/ollama/models');const d=await r.json();return d.models||[];}catch{return[];}}
1832
+ async function fetchRun(){try{const r=await fetch('/api/ollama/running');const d=await r.json();return d.models||[];}catch{return[];}}
1833
+ function fmtB(b){const g=b/(1024*1024*1024);return g>=1?g.toFixed(1)+' GB':(b/(1024*1024)).toFixed(0)+' MB';}
1834
+
1835
+ async function refreshModels(){
1836
+ const on=await checkOllama();
1837
+ if(!on){document.getElementById('installed-models').innerHTML='<div style="color:#556;font-size:11px">Start Ollama to see models</div>';document.getElementById('running-section').style.display='none';renderReco();return;}
1838
+ const[inst,run]=await Promise.all([fetchInst(),fetchRun()]);
1839
+ instNames=new Set(inst.map(m=>m.name)); runNames=new Set(run.map(m=>m.name));
1840
+ const rSec=document.getElementById('running-section'), rM=document.getElementById('running-models');
1841
+ if(run.length>0){rSec.style.display='block';rM.innerHTML='';for(const m of run){const c=document.createElement('div');c.className='model-card';c.innerHTML='<div class="mc-name">'+esc(m.name)+'</div><div class="mc-meta">'+(m.size?fmtB(m.size):'')+'</div><span class="mc-status running">\\u25B6 running</span>';rM.appendChild(c);}}else{rSec.style.display='none';}
1842
+ const iM=document.getElementById('installed-models');
1843
+ if(inst.length>0){iM.innerHTML='';for(const m of inst){const c=document.createElement('div');c.className='model-card';const isR=runNames.has(m.name);c.innerHTML='<div class="mc-name">'+esc(m.name)+'</div><div class="mc-meta">'+(m.size?fmtB(m.size):'')+'</div>'+(isR?'<span class="mc-status running">\\u25B6 running</span>':'<span class="mc-status installed">\\u2705 installed</span>')+'<div class="mc-actions"><button class="mc-btn primary" data-activate="'+esc(m.name)+'">\\u26A1 Activate</button><button class="mc-btn danger" data-delete="'+esc(m.name)+'">\\u{1F5D1} Delete</button></div>';iM.appendChild(c);}
1844
+ iM.querySelectorAll('[data-activate]').forEach(b=>{b.addEventListener('click',()=>{if(ws&&ws.readyState===WebSocket.OPEN){ws.send(JSON.stringify({type:'activate_model',model:b.dataset.activate}));b.textContent='\\u23F3...';b.disabled=true;}});});
1845
+ iM.querySelectorAll('[data-delete]').forEach(b=>{b.addEventListener('click',async()=>{if(!confirm('Delete '+b.dataset.delete+'?'))return;b.disabled=true;try{await fetch('/api/ollama/delete',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:b.dataset.delete})});}catch{}refreshModels();});});
1846
+ }else{iM.innerHTML='<div style="color:#556;font-size:11px">No models installed</div>';}
1847
+ renderReco();
1848
+ }
1849
+
1850
+ function renderReco(){
1851
+ const rM=document.getElementById('recommended-models'); rM.innerHTML='';
1852
+ const filt=RECO.filter(m=>m.vram<=curVram);
1853
+ if(!filt.length){rM.innerHTML='<div style="color:#556;font-size:11px">No models fit this VRAM</div>';return;}
1854
+ for(const m of filt){
1855
+ const inst=instNames.has(m.name), run=runNames.has(m.name);
1856
+ const c=document.createElement('div'); c.className='model-card';
1857
+ c.innerHTML='<div class="mc-name">'+esc(m.name)+'</div><div class="mc-meta">'+m.size+' VRAM</div><div class="mc-desc">'+esc(m.desc)+'</div>'+(run?'<span class="mc-status running">\\u25B6 running</span>':inst?'<span class="mc-status installed">\\u2705 installed</span>':'<span class="mc-status available">\\u2B07 available</span>')+(inst?'<div class="mc-actions"><button class="mc-btn primary" data-activate="'+esc(m.name)+'">\\u26A1 Activate</button></div>':'<div class="mc-actions"><button class="mc-btn" data-pull="'+esc(m.name)+'">\\u2B07 Download</button></div>');
1858
+ rM.appendChild(c);
1859
+ }
1860
+ rM.querySelectorAll('[data-pull]').forEach(b=>{b.addEventListener('click',()=>pullModel(b.dataset.pull,b));});
1861
+ rM.querySelectorAll('[data-activate]').forEach(b=>{b.addEventListener('click',()=>{if(ws&&ws.readyState===WebSocket.OPEN){ws.send(JSON.stringify({type:'activate_model',model:b.dataset.activate}));b.textContent='\\u23F3...';b.disabled=true;}});});
1862
+ }
1863
+
1864
+ async function pullModel(name,btn){
1865
+ if(!oOnline)return;
1866
+ btn.disabled=true; btn.textContent='Downloading...';
1867
+ try{
1868
+ const res=await fetch('/api/ollama/pull',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name})});
1869
+ if(!res.ok||!res.body){btn.textContent='\\u274C Failed';btn.disabled=false;return;}
1870
+ const reader=res.body.getReader(), dec=new TextDecoder();
1871
+ let buf='';
1872
+ while(true){
1873
+ const{done,value}=await reader.read(); if(done)break;
1874
+ buf+=dec.decode(value,{stream:true}); const lines=buf.split('\\n'); buf=lines.pop()||'';
1875
+ for(const ln of lines){
1876
+ if(!ln.startsWith('data: '))continue;
1877
+ try{const d=JSON.parse(ln.slice(6));if(d.status==='success'){btn.textContent='\\u2705 Installed';setTimeout(()=>refreshModels(),1000);return;}}catch{}
1878
+ }
1879
+ }
1880
+ btn.textContent='\\u2705 Done'; setTimeout(()=>refreshModels(),1000);
1881
+ }catch{btn.textContent='\\u274C Retry';btn.disabled=false;}
1882
+ }
1883
+ setInterval(()=>{if(mPanel.classList.contains('open'))refreshModels();},15000);
1884
+ checkOllama();
1885
+
1886
+ // ===== VOICE =====
1887
+ (function(){
1888
+ const SR=window.SpeechRecognition||window.webkitSpeechRecognition;
1889
+ const vP=document.getElementById('voice-panel'), vB=document.getElementById('voice-btn');
1890
+ const tr=document.getElementById('voice-transcript'), sB=document.getElementById('voice-send');
1891
+ const lS=document.getElementById('voice-lang'), stE=document.getElementById('voice-status');
1892
+ const wf=document.getElementById('voice-waveform');
1893
+ if(!SR){tr.textContent='Voice not supported';vB.style.opacity='0.3';vB.style.cursor='not-allowed';return;}
1894
+ for(let i=0;i<5;i++){const b=document.createElement('div');b.className='waveform-bar';b.style.animationDelay=(i*0.12)+'s';wf.appendChild(b);}
1895
+ let rec=null,isR=false,fT='',iT='';
1896
+ function mkRec(){
1897
+ const r=new SR();r.continuous=true;r.interimResults=true;r.lang=lS.value;r.maxAlternatives=1;
1898
+ r.onresult=(ev)=>{iT='';fT='';for(let i=0;i<ev.results.length;i++){if(ev.results[i].isFinal)fT+=ev.results[i][0].transcript;else iT+=ev.results[i][0].transcript;}tr.innerHTML=fT+(iT?'<span style="color:#556">'+esc(iT)+'</span>':'');tr.classList.remove('placeholder');if(fT.trim())sB.classList.add('visible');};
1899
+ r.onerror=(ev)=>{if(ev.error==='not-allowed'){stE.textContent='denied';tr.textContent='Microphone denied';tr.classList.add('placeholder');}stopR();};
1900
+ r.onend=()=>{if(isR)try{r.start();}catch{stopR();}};
1901
+ return r;
1902
+ }
1903
+ async function startR(){
1904
+ try{const s=await navigator.mediaDevices.getUserMedia({audio:true});s.getTracks().forEach(t=>t.stop());}catch{stE.textContent='denied';return;}
1905
+ rec=mkRec();fT='';iT='';isR=true;
1906
+ vB.classList.add('recording');vP.classList.add('recording');vB.textContent='\\u23F9';
1907
+ tr.innerHTML='<span style="color:#445;font-style:italic">Listening...</span>';tr.classList.remove('placeholder');sB.classList.remove('visible');
1908
+ stE.textContent='\\u25CF rec';stE.style.color='#ff3c3c';
1909
+ try{rec.start();}catch{stopR();}
1910
+ }
1911
+ function stopR(){
1912
+ isR=false;vB.classList.remove('recording');vP.classList.remove('recording');vB.textContent='\\u{1F3A4}';stE.textContent='';stE.style.color='';
1913
+ if(rec)try{rec.stop();}catch{} rec=null;
1914
+ if(fT.trim()){sB.classList.add('visible');tr.textContent=fT;}
1915
+ else if(!tr.textContent||tr.textContent==='Listening...'){tr.textContent='Click mic to speak...';tr.classList.add('placeholder');}
1916
+ }
1917
+ vB.addEventListener('click',()=>{isR?stopR():startR();});
1918
+ sB.addEventListener('click',()=>{
1919
+ const t=fT.trim();if(!t)return;
1920
+ const proto=location.protocol==='https:'?'wss:':'ws:';
1921
+ const sw=new WebSocket(proto+'//'+location.host);
1922
+ sw.onopen=()=>{sw.send(JSON.stringify({type:'voice_input',text:t}));stE.textContent='\\u2713 sent';stE.style.color='#00ff88';setTimeout(()=>{stE.textContent='';stE.style.color='';},2000);sw.close();};
1923
+ sw.onerror=()=>{stE.textContent='send failed';stE.style.color='#ff4444';};
1924
+ fT='';iT='';tr.textContent='Click mic to speak...';tr.classList.add('placeholder');sB.classList.remove('visible');
1925
+ });
1926
+ document.addEventListener('keydown',(e)=>{if(e.key==='Enter'&&!e.shiftKey&&fT.trim()&&sB.classList.contains('visible')){e.preventDefault();sB.click();}});
1927
+ lS.addEventListener('change',()=>{if(isR){stopR();startR();}});
1928
+ })();
1929
+
1930
+ // ===== BRAIN MANAGER =====
1931
+ const bmToggle=document.getElementById('brain-toggle');
1932
+ const bmPanel=document.getElementById('brain-manager');
1933
+ const bmGlobal=document.getElementById('bm-global');
1934
+ const bmLocal=document.getElementById('bm-local');
1935
+ const planItems=document.getElementById('plan-items');
1936
+ let brainListData=[];
1937
+ let selectedBrainId=null;
1938
+ let planTasks=new Map();
1939
+
1940
+ bmToggle.addEventListener('click',()=>{
1941
+ bmPanel.classList.toggle('open');
1942
+ bmToggle.classList.toggle('active');
1943
+ if(bmPanel.classList.contains('open')) requestBrainList();
1944
+ });
1945
+
1946
+ function requestBrainList(){
1947
+ if(ws&&ws.readyState===WebSocket.OPEN){
1948
+ ws.send(JSON.stringify({type:'get_brain_list',timestamp:Date.now()}));
1949
+ }
1950
+ }
1951
+
1952
+ function renderBrainList(brains,limits){
1953
+ brainListData=brains;
1954
+ bmGlobal.innerHTML='';
1955
+ bmLocal.innerHTML='';
1956
+ const globals=brains.filter(b=>b.type==='global');
1957
+ const locals=brains.filter(b=>b.type==='local');
1958
+
1959
+ if(globals.length===0) bmGlobal.innerHTML='<div style="font-size:10px;color:#334;padding:4px">No global brains</div>';
1960
+ globals.forEach(b=>bmGlobal.appendChild(createBrainCard(b)));
1961
+
1962
+ if(locals.length===0) bmLocal.innerHTML='<div style="font-size:10px;color:#334;padding:4px">No local brains</div>';
1963
+ locals.forEach(b=>bmLocal.appendChild(createBrainCard(b)));
1964
+
1965
+ if(!selectedBrainId&&brains.length>0){
1966
+ const active=brains.find(b=>b.active);
1967
+ if(active) selectBrainCard(active.id);
1968
+ }
1969
+ }
1970
+
1971
+ function createBrainCard(b){
1972
+ const card=document.createElement('div');
1973
+ card.className='brain-card'+(b.id===selectedBrainId?' selected':'');
1974
+ card.dataset.brainId=b.id;
1975
+
1976
+ const top=document.createElement('div');
1977
+ top.className='bc-top';
1978
+
1979
+ const dot=document.createElement('span');
1980
+ dot.className='bc-dot '+(b.active?'active':'inactive');
1981
+ dot.title=b.active?'Active':'Inactive';
1982
+
1983
+ const nameInput=document.createElement('input');
1984
+ nameInput.className='bc-name';
1985
+ nameInput.value=b.name;
1986
+ nameInput.readOnly=true;
1987
+ nameInput.addEventListener('blur',()=>{
1988
+ nameInput.readOnly=true;
1989
+ if(nameInput.value!==b.name&&nameInput.value.trim()){
1990
+ renameBrain(b.id,nameInput.value.trim());
1991
+ }
1992
+ });
1993
+ nameInput.addEventListener('keydown',(e)=>{
1994
+ if(e.key==='Enter'){nameInput.blur();e.preventDefault();}
1995
+ if(e.key==='Escape'){nameInput.value=b.name;nameInput.blur();}
1996
+ });
1997
+
1998
+ const editBtn=document.createElement('span');
1999
+ editBtn.className='bc-edit';
2000
+ editBtn.textContent='\\u270F\\uFE0F';
2001
+ editBtn.title='Rename';
2002
+ editBtn.addEventListener('click',(e)=>{
2003
+ e.stopPropagation();
2004
+ nameInput.readOnly=false;
2005
+ nameInput.focus();
2006
+ nameInput.select();
2007
+ });
2008
+
2009
+ top.appendChild(dot);
2010
+ top.appendChild(nameInput);
2011
+ top.appendChild(editBtn);
2012
+
2013
+ const meta=document.createElement('div');
2014
+ meta.className='bc-meta';
2015
+ meta.textContent=b.nodeCount+' nodes';
2016
+ if(b.projectPath){
2017
+ const short=b.projectPath.split('/').pop()||b.projectPath.split('\\\\').pop()||'';
2018
+ if(short) meta.textContent+=' \\u00B7 '+short;
2019
+ }
2020
+
2021
+ card.appendChild(top);
2022
+ card.appendChild(meta);
2023
+
2024
+ card.addEventListener('click',()=>{
2025
+ if(!nameInput.readOnly) return;
2026
+ switchBrain(b.id);
2027
+ });
2028
+
2029
+ return card;
2030
+ }
2031
+
2032
+ function switchBrain(brainId){
2033
+ if(ws&&ws.readyState===WebSocket.OPEN){
2034
+ ws.send(JSON.stringify({type:'switch_brain',brainId,timestamp:Date.now()}));
2035
+ }
2036
+ selectBrainCard(brainId);
2037
+ }
2038
+
2039
+ function selectBrainCard(brainId){
2040
+ selectedBrainId=brainId;
2041
+ document.querySelectorAll('.brain-card').forEach(c=>{
2042
+ c.classList.toggle('selected',c.dataset.brainId===brainId);
2043
+ });
2044
+ }
2045
+
2046
+ function renameBrain(brainId,newName){
2047
+ if(ws&&ws.readyState===WebSocket.OPEN){
2048
+ ws.send(JSON.stringify({type:'rename_brain',brainId,newName,timestamp:Date.now()}));
2049
+ }
2050
+ }
2051
+
2052
+ function updateBrainName(brainId,newName){
2053
+ const card=document.querySelector('.brain-card[data-brain-id="'+brainId+'"]');
2054
+ if(card){
2055
+ const inp=card.querySelector('.bc-name');
2056
+ if(inp) inp.value=newName;
2057
+ }
2058
+ }
2059
+
2060
+ function showLimitToast(limitType,current,max){
2061
+ const t=document.createElement('div');
2062
+ t.style.cssText='position:fixed;top:60px;left:50%;transform:translateX(-50%);background:rgba(255,100,0,0.15);border:1px solid rgba(255,100,0,0.3);color:#ff6600;padding:8px 20px;border-radius:8px;font-size:12px;z-index:999;backdrop-filter:blur(10px);';
2063
+ t.textContent='\\u26A0 Brain limit reached: '+current+'/'+max+' '+limitType+'. Upgrade for more.';
2064
+ document.body.appendChild(t);
2065
+ setTimeout(()=>t.remove(),4000);
2066
+ }
2067
+
2068
+ // Plan View (Jarvis Tasks)
2069
+ function updatePlanView(task){
2070
+ if(!task||!task.id) return;
2071
+ planTasks.set(task.id,task);
2072
+ renderPlanItems();
2073
+ }
2074
+
2075
+ function renderPlanItems(){
2076
+ if(planTasks.size===0){
2077
+ planItems.innerHTML='<div class="plan-item pending"><span class="pi-icon">\\u25CB</span><span class="pi-text" style="color:#445">No active tasks</span></div>';
2078
+ return;
2079
+ }
2080
+ planItems.innerHTML='';
2081
+ const sorted=[...planTasks.values()].sort((a,b)=>a.id-b.id);
2082
+ sorted.forEach(task=>{
2083
+ const item=document.createElement('div');
2084
+ item.className='plan-item '+(task.status||'pending');
2085
+ const icons={pending:'\\u25CB',running:'\\u23F3',completed:'\\u2714',failed:'\\u2718',paused:'\\u23F8'};
2086
+ item.innerHTML='<span class="pi-icon">'+(icons[task.status]||'\\u25CB')+'</span><span class="pi-text">'+esc(task.title||'Untitled')+'</span>';
2087
+ planItems.appendChild(item);
2088
+ });
2089
+ }
2090
+
2091
+ // ===== START =====
2092
+ lastNodeIds=BRAIN_DATA.nodes.map(n=>n.id).sort().join(',');
2093
+ buildScene();
2094
+ animate();
2095
+ </script>
2096
+ </body>
2097
+ </html>`;
2098
+ }
2099
+ //# sourceMappingURL=template.js.map