synabun 1.3.0 → 2.0.0-beta

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 (1153) hide show
  1. package/CHANGELOG.md +197 -662
  2. package/LICENSE-COMMERCIAL.md +33 -0
  3. package/NOTICE +17 -0
  4. package/README.md +175 -853
  5. package/THIRD-PARTY-LICENSES.md +131 -0
  6. package/benchmarks/browser-live-results.json +79 -0
  7. package/benchmarks/browser-v2-results.json +258 -0
  8. package/benchmarks/fixtures/browser/README.md +57 -0
  9. package/benchmarks/fixtures/browser/page-state.json +132 -0
  10. package/benchmarks/fixtures/browser/social.json +92 -0
  11. package/benchmarks/fixtures/browser/target.json +319 -0
  12. package/benchmarks/fixtures/desktop/README.md +58 -0
  13. package/benchmarks/fixtures/desktop/abstention.json +59 -0
  14. package/benchmarks/fixtures/desktop/adversarial.json +22 -0
  15. package/benchmarks/fixtures/desktop/forbidden.json +93 -0
  16. package/benchmarks/fixtures/desktop/generate.mjs +1023 -0
  17. package/benchmarks/fixtures/desktop/target.json +136 -0
  18. package/bin/synabun.js +30 -0
  19. package/docs/browser-v2.md +109 -0
  20. package/docs/hook-integrity.md +89 -0
  21. package/docs/judgments.md +182 -0
  22. package/docs/style-guide.md +246 -0
  23. package/docs/whatsapp.md +325 -0
  24. package/hooks/claude-code/post-plan.mjs +613 -391
  25. package/hooks/claude-code/post-remember.mjs +246 -122
  26. package/hooks/claude-code/pre-compact.mjs +171 -110
  27. package/hooks/claude-code/pre-task.mjs +133 -0
  28. package/hooks/claude-code/pre-websearch.mjs +15 -4
  29. package/hooks/claude-code/prompt-origin.mjs +94 -0
  30. package/hooks/claude-code/prompt-submit.mjs +1244 -861
  31. package/hooks/claude-code/session-start.mjs +114 -156
  32. package/hooks/claude-code/shared.mjs +1228 -368
  33. package/hooks/claude-code/state.mjs +167 -0
  34. package/hooks/claude-code/stop.mjs +515 -140
  35. package/hooks/claude-code/subagent-start.mjs +154 -0
  36. package/hooks/claude-code/subagent-stop.mjs +102 -0
  37. package/hooks/claude-code/task-gate.mjs +150 -0
  38. package/lib/claude-hooks.js +84 -0
  39. package/lib/claude-usage-audit.js +141 -0
  40. package/lib/client-config-repair.js +144 -0
  41. package/lib/data-home-migration.js +498 -0
  42. package/lib/first-launch-protection.js +240 -0
  43. package/lib/paths.d.ts +21 -0
  44. package/lib/paths.js +103 -0
  45. package/mcp-server/dist/config.d.ts +22 -0
  46. package/mcp-server/dist/config.d.ts.map +1 -0
  47. package/mcp-server/dist/config.js +109 -0
  48. package/mcp-server/dist/config.js.map +1 -0
  49. package/mcp-server/dist/http.d.ts +30 -0
  50. package/mcp-server/dist/http.d.ts.map +1 -0
  51. package/mcp-server/dist/http.js +276 -0
  52. package/mcp-server/dist/http.js.map +1 -0
  53. package/mcp-server/dist/index.d.ts +48 -0
  54. package/mcp-server/dist/index.d.ts.map +1 -0
  55. package/mcp-server/dist/index.js +538 -0
  56. package/mcp-server/dist/index.js.map +1 -0
  57. package/mcp-server/dist/preload-http.d.ts +3 -0
  58. package/mcp-server/dist/preload-http.d.ts.map +1 -0
  59. package/mcp-server/dist/preload-http.js +28 -0
  60. package/mcp-server/dist/preload-http.js.map +1 -0
  61. package/mcp-server/dist/preload.d.ts +3 -0
  62. package/mcp-server/dist/preload.d.ts.map +1 -0
  63. package/mcp-server/dist/preload.js +32 -0
  64. package/mcp-server/dist/preload.js.map +1 -0
  65. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts +19 -0
  66. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts.map +1 -0
  67. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js +403 -0
  68. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js.map +1 -0
  69. package/mcp-server/dist/scripts/setup-embeddings.d.ts +3 -0
  70. package/mcp-server/dist/scripts/setup-embeddings.d.ts.map +1 -0
  71. package/mcp-server/dist/scripts/setup-embeddings.js +15 -0
  72. package/mcp-server/dist/scripts/setup-embeddings.js.map +1 -0
  73. package/mcp-server/dist/services/assistant-judgments.d.ts +79 -0
  74. package/mcp-server/dist/services/assistant-judgments.d.ts.map +1 -0
  75. package/mcp-server/dist/services/assistant-judgments.js +128 -0
  76. package/mcp-server/dist/services/assistant-judgments.js.map +1 -0
  77. package/mcp-server/dist/services/browser-assist-gate.d.ts +314 -0
  78. package/mcp-server/dist/services/browser-assist-gate.d.ts.map +1 -0
  79. package/mcp-server/dist/services/browser-assist-gate.js +344 -0
  80. package/mcp-server/dist/services/browser-assist-gate.js.map +1 -0
  81. package/mcp-server/dist/services/browser-assist.d.ts +104 -0
  82. package/mcp-server/dist/services/browser-assist.d.ts.map +1 -0
  83. package/mcp-server/dist/services/browser-assist.js +282 -0
  84. package/mcp-server/dist/services/browser-assist.js.map +1 -0
  85. package/mcp-server/dist/services/browser-bench.d.ts +772 -0
  86. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -0
  87. package/mcp-server/dist/services/browser-bench.js +424 -0
  88. package/mcp-server/dist/services/browser-bench.js.map +1 -0
  89. package/mcp-server/dist/services/browser-judgments.d.ts +196 -0
  90. package/mcp-server/dist/services/browser-judgments.d.ts.map +1 -0
  91. package/mcp-server/dist/services/browser-judgments.js +363 -0
  92. package/mcp-server/dist/services/browser-judgments.js.map +1 -0
  93. package/mcp-server/dist/services/browser-risk.d.ts +166 -0
  94. package/mcp-server/dist/services/browser-risk.d.ts.map +1 -0
  95. package/mcp-server/dist/services/browser-risk.js +458 -0
  96. package/mcp-server/dist/services/browser-risk.js.map +1 -0
  97. package/mcp-server/dist/services/categories.d.ts +61 -0
  98. package/mcp-server/dist/services/categories.d.ts.map +1 -0
  99. package/mcp-server/dist/services/categories.js +377 -0
  100. package/mcp-server/dist/services/categories.js.map +1 -0
  101. package/mcp-server/dist/services/codex-config-heal.d.ts +49 -0
  102. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -0
  103. package/mcp-server/dist/services/codex-config-heal.js +346 -0
  104. package/mcp-server/dist/services/codex-config-heal.js.map +1 -0
  105. package/mcp-server/dist/services/desktop-assist-gate.d.ts +198 -0
  106. package/mcp-server/dist/services/desktop-assist-gate.d.ts.map +1 -0
  107. package/mcp-server/dist/services/desktop-assist-gate.js +202 -0
  108. package/mcp-server/dist/services/desktop-assist-gate.js.map +1 -0
  109. package/mcp-server/dist/services/desktop-assist.d.ts +104 -0
  110. package/mcp-server/dist/services/desktop-assist.d.ts.map +1 -0
  111. package/mcp-server/dist/services/desktop-assist.js +266 -0
  112. package/mcp-server/dist/services/desktop-assist.js.map +1 -0
  113. package/mcp-server/dist/services/desktop-bench.d.ts +553 -0
  114. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -0
  115. package/mcp-server/dist/services/desktop-bench.js +311 -0
  116. package/mcp-server/dist/services/desktop-bench.js.map +1 -0
  117. package/mcp-server/dist/services/desktop-client.d.ts +23 -0
  118. package/mcp-server/dist/services/desktop-client.d.ts.map +1 -0
  119. package/mcp-server/dist/services/desktop-client.js +79 -0
  120. package/mcp-server/dist/services/desktop-client.js.map +1 -0
  121. package/mcp-server/dist/services/desktop-judgments.d.ts +125 -0
  122. package/mcp-server/dist/services/desktop-judgments.d.ts.map +1 -0
  123. package/mcp-server/dist/services/desktop-judgments.js +177 -0
  124. package/mcp-server/dist/services/desktop-judgments.js.map +1 -0
  125. package/mcp-server/dist/services/desktop-risk.d.ts +283 -0
  126. package/mcp-server/dist/services/desktop-risk.d.ts.map +1 -0
  127. package/mcp-server/dist/services/desktop-risk.js +605 -0
  128. package/mcp-server/dist/services/desktop-risk.js.map +1 -0
  129. package/mcp-server/dist/services/discord.d.ts +112 -0
  130. package/mcp-server/dist/services/discord.d.ts.map +1 -0
  131. package/mcp-server/dist/services/discord.js +477 -0
  132. package/mcp-server/dist/services/discord.js.map +1 -0
  133. package/mcp-server/dist/services/edit-stale.d.ts +81 -0
  134. package/mcp-server/dist/services/edit-stale.d.ts.map +1 -0
  135. package/mcp-server/dist/services/edit-stale.js +358 -0
  136. package/mcp-server/dist/services/edit-stale.js.map +1 -0
  137. package/mcp-server/dist/services/embedding-service.d.ts +16 -0
  138. package/mcp-server/dist/services/embedding-service.d.ts.map +1 -0
  139. package/mcp-server/dist/services/embedding-service.js +126 -0
  140. package/mcp-server/dist/services/embedding-service.js.map +1 -0
  141. package/mcp-server/dist/services/embedding-worker.d.ts +2 -0
  142. package/mcp-server/dist/services/embedding-worker.d.ts.map +1 -0
  143. package/mcp-server/dist/services/embedding-worker.js +52 -0
  144. package/mcp-server/dist/services/embedding-worker.js.map +1 -0
  145. package/mcp-server/dist/services/fb-regions.d.ts +71 -0
  146. package/mcp-server/dist/services/fb-regions.d.ts.map +1 -0
  147. package/mcp-server/dist/services/fb-regions.js +211 -0
  148. package/mcp-server/dist/services/fb-regions.js.map +1 -0
  149. package/mcp-server/dist/services/file-checksums.d.ts +22 -0
  150. package/mcp-server/dist/services/file-checksums.d.ts.map +1 -0
  151. package/mcp-server/dist/services/file-checksums.js +55 -0
  152. package/mcp-server/dist/services/file-checksums.js.map +1 -0
  153. package/mcp-server/dist/services/file-excerpt.d.ts +24 -0
  154. package/mcp-server/dist/services/file-excerpt.d.ts.map +1 -0
  155. package/mcp-server/dist/services/file-excerpt.js +65 -0
  156. package/mcp-server/dist/services/file-excerpt.js.map +1 -0
  157. package/mcp-server/dist/services/identity.d.ts +124 -0
  158. package/mcp-server/dist/services/identity.d.ts.map +1 -0
  159. package/mcp-server/dist/services/identity.js +241 -0
  160. package/mcp-server/dist/services/identity.js.map +1 -0
  161. package/mcp-server/dist/services/local-embeddings.d.ts +2 -0
  162. package/mcp-server/dist/services/local-embeddings.d.ts.map +1 -0
  163. package/mcp-server/dist/services/local-embeddings.js +3 -0
  164. package/mcp-server/dist/services/local-embeddings.js.map +1 -0
  165. package/mcp-server/dist/services/memory-client.d.ts +4 -0
  166. package/mcp-server/dist/services/memory-client.d.ts.map +1 -0
  167. package/mcp-server/dist/services/memory-client.js +27 -0
  168. package/mcp-server/dist/services/memory-client.js.map +1 -0
  169. package/mcp-server/dist/services/memory-judge-backfill.d.ts +135 -0
  170. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -0
  171. package/mcp-server/dist/services/memory-judge-backfill.js +510 -0
  172. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -0
  173. package/mcp-server/dist/services/memory-judgments.d.ts +362 -0
  174. package/mcp-server/dist/services/memory-judgments.d.ts.map +1 -0
  175. package/mcp-server/dist/services/memory-judgments.js +674 -0
  176. package/mcp-server/dist/services/memory-judgments.js.map +1 -0
  177. package/mcp-server/dist/services/memory-maintenance.d.ts +108 -0
  178. package/mcp-server/dist/services/memory-maintenance.d.ts.map +1 -0
  179. package/mcp-server/dist/services/memory-maintenance.js +403 -0
  180. package/mcp-server/dist/services/memory-maintenance.js.map +1 -0
  181. package/mcp-server/dist/services/memory-retrieval.d.ts +66 -0
  182. package/mcp-server/dist/services/memory-retrieval.d.ts.map +1 -0
  183. package/mcp-server/dist/services/memory-retrieval.js +412 -0
  184. package/mcp-server/dist/services/memory-retrieval.js.map +1 -0
  185. package/mcp-server/dist/services/memory-schema.d.ts +16 -0
  186. package/mcp-server/dist/services/memory-schema.d.ts.map +1 -0
  187. package/mcp-server/dist/services/memory-schema.js +282 -0
  188. package/mcp-server/dist/services/memory-schema.js.map +1 -0
  189. package/mcp-server/dist/services/memory-sessions.d.ts +24 -0
  190. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -0
  191. package/mcp-server/dist/services/memory-sessions.js +110 -0
  192. package/mcp-server/dist/services/memory-sessions.js.map +1 -0
  193. package/mcp-server/dist/services/memory-triage.d.ts +60 -0
  194. package/mcp-server/dist/services/memory-triage.d.ts.map +1 -0
  195. package/mcp-server/dist/services/memory-triage.js +189 -0
  196. package/mcp-server/dist/services/memory-triage.js.map +1 -0
  197. package/mcp-server/dist/services/memory-verification.d.ts +24 -0
  198. package/mcp-server/dist/services/memory-verification.d.ts.map +1 -0
  199. package/mcp-server/dist/services/memory-verification.js +92 -0
  200. package/mcp-server/dist/services/memory-verification.js.map +1 -0
  201. package/mcp-server/dist/services/memory-writer.d.ts +26 -0
  202. package/mcp-server/dist/services/memory-writer.d.ts.map +1 -0
  203. package/mcp-server/dist/services/memory-writer.js +126 -0
  204. package/mcp-server/dist/services/memory-writer.js.map +1 -0
  205. package/mcp-server/dist/services/neural-interface.d.ts +439 -0
  206. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -0
  207. package/mcp-server/dist/services/neural-interface.js +1135 -0
  208. package/mcp-server/dist/services/neural-interface.js.map +1 -0
  209. package/mcp-server/dist/services/profiles.d.ts +120 -0
  210. package/mcp-server/dist/services/profiles.d.ts.map +1 -0
  211. package/mcp-server/dist/services/profiles.js +387 -0
  212. package/mcp-server/dist/services/profiles.js.map +1 -0
  213. package/mcp-server/dist/services/secret-gate.d.ts +29 -0
  214. package/mcp-server/dist/services/secret-gate.d.ts.map +1 -0
  215. package/mcp-server/dist/services/secret-gate.js +43 -0
  216. package/mcp-server/dist/services/secret-gate.js.map +1 -0
  217. package/mcp-server/dist/services/server-instructions.d.ts +10 -0
  218. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -0
  219. package/mcp-server/dist/services/server-instructions.js +101 -0
  220. package/mcp-server/dist/services/server-instructions.js.map +1 -0
  221. package/mcp-server/dist/services/sqlite.d.ts +235 -0
  222. package/mcp-server/dist/services/sqlite.d.ts.map +1 -0
  223. package/mcp-server/dist/services/sqlite.js +1185 -0
  224. package/mcp-server/dist/services/sqlite.js.map +1 -0
  225. package/mcp-server/dist/services/typesafe-bench.d.ts +99 -0
  226. package/mcp-server/dist/services/typesafe-bench.d.ts.map +1 -0
  227. package/mcp-server/dist/services/typesafe-bench.js +218 -0
  228. package/mcp-server/dist/services/typesafe-bench.js.map +1 -0
  229. package/mcp-server/dist/services/typesafe-config.d.ts +342 -0
  230. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -0
  231. package/mcp-server/dist/services/typesafe-config.js +746 -0
  232. package/mcp-server/dist/services/typesafe-config.js.map +1 -0
  233. package/mcp-server/dist/services/typesafe.d.ts +213 -0
  234. package/mcp-server/dist/services/typesafe.d.ts.map +1 -0
  235. package/mcp-server/dist/services/typesafe.js +330 -0
  236. package/mcp-server/dist/services/typesafe.js.map +1 -0
  237. package/mcp-server/dist/services/vector-cache.d.ts +68 -0
  238. package/mcp-server/dist/services/vector-cache.d.ts.map +1 -0
  239. package/mcp-server/dist/services/vector-cache.js +271 -0
  240. package/mcp-server/dist/services/vector-cache.js.map +1 -0
  241. package/mcp-server/dist/services/whiteboard-geometry.d.ts +305 -0
  242. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -0
  243. package/mcp-server/dist/services/whiteboard-geometry.js +666 -0
  244. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -0
  245. package/mcp-server/dist/tools/agents.d.ts +212 -0
  246. package/mcp-server/dist/tools/agents.d.ts.map +1 -0
  247. package/mcp-server/dist/tools/agents.js +407 -0
  248. package/mcp-server/dist/tools/agents.js.map +1 -0
  249. package/mcp-server/dist/tools/bluesky.d.ts +39 -0
  250. package/mcp-server/dist/tools/bluesky.d.ts.map +1 -0
  251. package/mcp-server/dist/tools/bluesky.js +1144 -0
  252. package/mcp-server/dist/tools/bluesky.js.map +1 -0
  253. package/mcp-server/dist/tools/browser-advanced.d.ts +58 -0
  254. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -0
  255. package/mcp-server/dist/tools/browser-advanced.js +106 -0
  256. package/mcp-server/dist/tools/browser-advanced.js.map +1 -0
  257. package/mcp-server/dist/tools/browser-batch.d.ts +99 -0
  258. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -0
  259. package/mcp-server/dist/tools/browser-batch.js +187 -0
  260. package/mcp-server/dist/tools/browser-batch.js.map +1 -0
  261. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +21 -0
  262. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -0
  263. package/mcp-server/dist/tools/browser-cheatsheet.js +144 -0
  264. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -0
  265. package/mcp-server/dist/tools/browser-interact.d.ts +239 -0
  266. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -0
  267. package/mcp-server/dist/tools/browser-interact.js +300 -0
  268. package/mcp-server/dist/tools/browser-interact.js.map +1 -0
  269. package/mcp-server/dist/tools/browser-navigate.d.ts +90 -0
  270. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -0
  271. package/mcp-server/dist/tools/browser-navigate.js +142 -0
  272. package/mcp-server/dist/tools/browser-navigate.js.map +1 -0
  273. package/mcp-server/dist/tools/browser-observe.d.ts +561 -0
  274. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -0
  275. package/mcp-server/dist/tools/browser-observe.js +2009 -0
  276. package/mcp-server/dist/tools/browser-observe.js.map +1 -0
  277. package/mcp-server/dist/tools/browser.d.ts +34 -0
  278. package/mcp-server/dist/tools/browser.d.ts.map +1 -0
  279. package/mcp-server/dist/tools/browser.js +112 -0
  280. package/mcp-server/dist/tools/browser.js.map +1 -0
  281. package/mcp-server/dist/tools/card-tools.d.ts +82 -0
  282. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -0
  283. package/mcp-server/dist/tools/card-tools.js +137 -0
  284. package/mcp-server/dist/tools/card-tools.js.map +1 -0
  285. package/mcp-server/dist/tools/card.d.ts +8 -0
  286. package/mcp-server/dist/tools/card.d.ts.map +1 -0
  287. package/mcp-server/dist/tools/card.js +16 -0
  288. package/mcp-server/dist/tools/card.js.map +1 -0
  289. package/mcp-server/dist/tools/category.d.ts +32 -0
  290. package/mcp-server/dist/tools/category.d.ts.map +1 -0
  291. package/mcp-server/dist/tools/category.js +290 -0
  292. package/mcp-server/dist/tools/category.js.map +1 -0
  293. package/mcp-server/dist/tools/choice.d.ts +160 -0
  294. package/mcp-server/dist/tools/choice.d.ts.map +1 -0
  295. package/mcp-server/dist/tools/choice.js +80 -0
  296. package/mcp-server/dist/tools/choice.js.map +1 -0
  297. package/mcp-server/dist/tools/computer.d.ts +71 -0
  298. package/mcp-server/dist/tools/computer.d.ts.map +1 -0
  299. package/mcp-server/dist/tools/computer.js +174 -0
  300. package/mcp-server/dist/tools/computer.js.map +1 -0
  301. package/mcp-server/dist/tools/discord-channel.d.ts +44 -0
  302. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -0
  303. package/mcp-server/dist/tools/discord-channel.js +236 -0
  304. package/mcp-server/dist/tools/discord-channel.js.map +1 -0
  305. package/mcp-server/dist/tools/discord-guild.d.ts +20 -0
  306. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -0
  307. package/mcp-server/dist/tools/discord-guild.js +138 -0
  308. package/mcp-server/dist/tools/discord-guild.js.map +1 -0
  309. package/mcp-server/dist/tools/discord-member.d.ts +26 -0
  310. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -0
  311. package/mcp-server/dist/tools/discord-member.js +122 -0
  312. package/mcp-server/dist/tools/discord-member.js.map +1 -0
  313. package/mcp-server/dist/tools/discord-message.d.ts +36 -0
  314. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -0
  315. package/mcp-server/dist/tools/discord-message.js +184 -0
  316. package/mcp-server/dist/tools/discord-message.js.map +1 -0
  317. package/mcp-server/dist/tools/discord-onboarding.d.ts +32 -0
  318. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -0
  319. package/mcp-server/dist/tools/discord-onboarding.js +179 -0
  320. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -0
  321. package/mcp-server/dist/tools/discord-role.d.ts +34 -0
  322. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -0
  323. package/mcp-server/dist/tools/discord-role.js +178 -0
  324. package/mcp-server/dist/tools/discord-role.js.map +1 -0
  325. package/mcp-server/dist/tools/discord-thread.d.ts +28 -0
  326. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -0
  327. package/mcp-server/dist/tools/discord-thread.js +88 -0
  328. package/mcp-server/dist/tools/discord-thread.js.map +1 -0
  329. package/mcp-server/dist/tools/discord-webhook.d.ts +32 -0
  330. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -0
  331. package/mcp-server/dist/tools/discord-webhook.js +154 -0
  332. package/mcp-server/dist/tools/discord-webhook.js.map +1 -0
  333. package/mcp-server/dist/tools/discord.d.ts +7 -0
  334. package/mcp-server/dist/tools/discord.d.ts.map +1 -0
  335. package/mcp-server/dist/tools/discord.js +25 -0
  336. package/mcp-server/dist/tools/discord.js.map +1 -0
  337. package/mcp-server/dist/tools/fb-groups.d.ts +98 -0
  338. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -0
  339. package/mcp-server/dist/tools/fb-groups.js +369 -0
  340. package/mcp-server/dist/tools/fb-groups.js.map +1 -0
  341. package/mcp-server/dist/tools/forget.d.ts +14 -0
  342. package/mcp-server/dist/tools/forget.d.ts.map +1 -0
  343. package/mcp-server/dist/tools/forget.js +26 -0
  344. package/mcp-server/dist/tools/forget.js.map +1 -0
  345. package/mcp-server/dist/tools/git-tools.d.ts +24 -0
  346. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -0
  347. package/mcp-server/dist/tools/git-tools.js +107 -0
  348. package/mcp-server/dist/tools/git-tools.js.map +1 -0
  349. package/mcp-server/dist/tools/git.d.ts +7 -0
  350. package/mcp-server/dist/tools/git.d.ts.map +1 -0
  351. package/mcp-server/dist/tools/git.js +11 -0
  352. package/mcp-server/dist/tools/git.js.map +1 -0
  353. package/mcp-server/dist/tools/gsc/experience.d.ts +135 -0
  354. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -0
  355. package/mcp-server/dist/tools/gsc/experience.js +351 -0
  356. package/mcp-server/dist/tools/gsc/experience.js.map +1 -0
  357. package/mcp-server/dist/tools/gsc/helpers.d.ts +78 -0
  358. package/mcp-server/dist/tools/gsc/helpers.d.ts.map +1 -0
  359. package/mcp-server/dist/tools/gsc/helpers.js +258 -0
  360. package/mcp-server/dist/tools/gsc/helpers.js.map +1 -0
  361. package/mcp-server/dist/tools/gsc/indexing.d.ts +121 -0
  362. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -0
  363. package/mcp-server/dist/tools/gsc/indexing.js +357 -0
  364. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -0
  365. package/mcp-server/dist/tools/gsc/inspect.d.ts +78 -0
  366. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -0
  367. package/mcp-server/dist/tools/gsc/inspect.js +321 -0
  368. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -0
  369. package/mcp-server/dist/tools/gsc/navigate.d.ts +44 -0
  370. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -0
  371. package/mcp-server/dist/tools/gsc/navigate.js +197 -0
  372. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -0
  373. package/mcp-server/dist/tools/gsc/performance.d.ts +84 -0
  374. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -0
  375. package/mcp-server/dist/tools/gsc/performance.js +274 -0
  376. package/mcp-server/dist/tools/gsc/performance.js.map +1 -0
  377. package/mcp-server/dist/tools/gsc/settings.d.ts +153 -0
  378. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -0
  379. package/mcp-server/dist/tools/gsc/settings.js +425 -0
  380. package/mcp-server/dist/tools/gsc/settings.js.map +1 -0
  381. package/mcp-server/dist/tools/gsc.d.ts +7 -0
  382. package/mcp-server/dist/tools/gsc.d.ts.map +1 -0
  383. package/mcp-server/dist/tools/gsc.js +51 -0
  384. package/mcp-server/dist/tools/gsc.js.map +1 -0
  385. package/mcp-server/dist/tools/image-tools.d.ts +24 -0
  386. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -0
  387. package/mcp-server/dist/tools/image-tools.js +80 -0
  388. package/mcp-server/dist/tools/image-tools.js.map +1 -0
  389. package/mcp-server/dist/tools/image.d.ts +10 -0
  390. package/mcp-server/dist/tools/image.d.ts.map +1 -0
  391. package/mcp-server/dist/tools/image.js +14 -0
  392. package/mcp-server/dist/tools/image.js.map +1 -0
  393. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +97 -0
  394. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -0
  395. package/mcp-server/dist/tools/leonardo-browser-tools.js +228 -0
  396. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -0
  397. package/mcp-server/dist/tools/leonardo.d.ts +13 -0
  398. package/mcp-server/dist/tools/leonardo.d.ts.map +1 -0
  399. package/mcp-server/dist/tools/leonardo.js +21 -0
  400. package/mcp-server/dist/tools/leonardo.js.map +1 -0
  401. package/mcp-server/dist/tools/loop.d.ts +30 -0
  402. package/mcp-server/dist/tools/loop.d.ts.map +1 -0
  403. package/mcp-server/dist/tools/loop.js +401 -0
  404. package/mcp-server/dist/tools/loop.js.map +1 -0
  405. package/mcp-server/dist/tools/memories.d.ts +56 -0
  406. package/mcp-server/dist/tools/memories.d.ts.map +1 -0
  407. package/mcp-server/dist/tools/memories.js +171 -0
  408. package/mcp-server/dist/tools/memories.js.map +1 -0
  409. package/mcp-server/dist/tools/morelogin.d.ts +24 -0
  410. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -0
  411. package/mcp-server/dist/tools/morelogin.js +79 -0
  412. package/mcp-server/dist/tools/morelogin.js.map +1 -0
  413. package/mcp-server/dist/tools/profile.d.ts +17 -0
  414. package/mcp-server/dist/tools/profile.d.ts.map +1 -0
  415. package/mcp-server/dist/tools/profile.js +114 -0
  416. package/mcp-server/dist/tools/profile.js.map +1 -0
  417. package/mcp-server/dist/tools/recall.d.ts +71 -0
  418. package/mcp-server/dist/tools/recall.d.ts.map +1 -0
  419. package/mcp-server/dist/tools/recall.js +147 -0
  420. package/mcp-server/dist/tools/recall.js.map +1 -0
  421. package/mcp-server/dist/tools/reflect.d.ts +56 -0
  422. package/mcp-server/dist/tools/reflect.d.ts.map +1 -0
  423. package/mcp-server/dist/tools/reflect.js +157 -0
  424. package/mcp-server/dist/tools/reflect.js.map +1 -0
  425. package/mcp-server/dist/tools/remember.d.ts +62 -0
  426. package/mcp-server/dist/tools/remember.d.ts.map +1 -0
  427. package/mcp-server/dist/tools/remember.js +201 -0
  428. package/mcp-server/dist/tools/remember.js.map +1 -0
  429. package/mcp-server/dist/tools/response.d.ts +23 -0
  430. package/mcp-server/dist/tools/response.d.ts.map +1 -0
  431. package/mcp-server/dist/tools/response.js +24 -0
  432. package/mcp-server/dist/tools/response.js.map +1 -0
  433. package/mcp-server/dist/tools/restore.d.ts +14 -0
  434. package/mcp-server/dist/tools/restore.d.ts.map +1 -0
  435. package/mcp-server/dist/tools/restore.js +23 -0
  436. package/mcp-server/dist/tools/restore.js.map +1 -0
  437. package/mcp-server/dist/tools/style-guide-tools.d.ts +51 -0
  438. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -0
  439. package/mcp-server/dist/tools/style-guide-tools.js +231 -0
  440. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -0
  441. package/mcp-server/dist/tools/style-guide.d.ts +8 -0
  442. package/mcp-server/dist/tools/style-guide.d.ts.map +1 -0
  443. package/mcp-server/dist/tools/style-guide.js +12 -0
  444. package/mcp-server/dist/tools/style-guide.js.map +1 -0
  445. package/mcp-server/dist/tools/sync.d.ts +20 -0
  446. package/mcp-server/dist/tools/sync.d.ts.map +1 -0
  447. package/mcp-server/dist/tools/sync.js +156 -0
  448. package/mcp-server/dist/tools/sync.js.map +1 -0
  449. package/mcp-server/dist/tools/tictactoe-tools.d.ts +18 -0
  450. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -0
  451. package/mcp-server/dist/tools/tictactoe-tools.js +78 -0
  452. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -0
  453. package/mcp-server/dist/tools/tictactoe.d.ts +7 -0
  454. package/mcp-server/dist/tools/tictactoe.d.ts.map +1 -0
  455. package/mcp-server/dist/tools/tictactoe.js +11 -0
  456. package/mcp-server/dist/tools/tictactoe.js.map +1 -0
  457. package/mcp-server/dist/tools/utils.d.ts +19 -0
  458. package/mcp-server/dist/tools/utils.d.ts.map +1 -0
  459. package/mcp-server/dist/tools/utils.js +54 -0
  460. package/mcp-server/dist/tools/utils.js.map +1 -0
  461. package/mcp-server/dist/tools/whiteboard-format.d.ts +88 -0
  462. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -0
  463. package/mcp-server/dist/tools/whiteboard-format.js +337 -0
  464. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -0
  465. package/mcp-server/dist/tools/whiteboard-tools.d.ts +326 -0
  466. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -0
  467. package/mcp-server/dist/tools/whiteboard-tools.js +222 -0
  468. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -0
  469. package/mcp-server/dist/tools/whiteboard.d.ts +8 -0
  470. package/mcp-server/dist/tools/whiteboard.d.ts.map +1 -0
  471. package/mcp-server/dist/tools/whiteboard.js +16 -0
  472. package/mcp-server/dist/tools/whiteboard.js.map +1 -0
  473. package/mcp-server/dist/tools/youtube/analytics.d.ts +46 -0
  474. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -0
  475. package/mcp-server/dist/tools/youtube/analytics.js +83 -0
  476. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -0
  477. package/mcp-server/dist/tools/youtube/dedup.d.ts +35 -0
  478. package/mcp-server/dist/tools/youtube/dedup.d.ts.map +1 -0
  479. package/mcp-server/dist/tools/youtube/dedup.js +56 -0
  480. package/mcp-server/dist/tools/youtube/dedup.js.map +1 -0
  481. package/mcp-server/dist/tools/youtube/download.d.ts +31 -0
  482. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -0
  483. package/mcp-server/dist/tools/youtube/download.js +30 -0
  484. package/mcp-server/dist/tools/youtube/download.js.map +1 -0
  485. package/mcp-server/dist/tools/youtube/helpers.d.ts +66 -0
  486. package/mcp-server/dist/tools/youtube/helpers.d.ts.map +1 -0
  487. package/mcp-server/dist/tools/youtube/helpers.js +143 -0
  488. package/mcp-server/dist/tools/youtube/helpers.js.map +1 -0
  489. package/mcp-server/dist/tools/youtube/media.d.ts +43 -0
  490. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -0
  491. package/mcp-server/dist/tools/youtube/media.js +97 -0
  492. package/mcp-server/dist/tools/youtube/media.js.map +1 -0
  493. package/mcp-server/dist/tools/youtube/metadata.d.ts +33 -0
  494. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -0
  495. package/mcp-server/dist/tools/youtube/metadata.js +106 -0
  496. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -0
  497. package/mcp-server/dist/tools/youtube/navigate.d.ts +30 -0
  498. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -0
  499. package/mcp-server/dist/tools/youtube/navigate.js +71 -0
  500. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -0
  501. package/mcp-server/dist/tools/youtube/playlist.d.ts +29 -0
  502. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -0
  503. package/mcp-server/dist/tools/youtube/playlist.js +128 -0
  504. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -0
  505. package/mcp-server/dist/tools/youtube/schedule.d.ts +31 -0
  506. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -0
  507. package/mcp-server/dist/tools/youtube/schedule.js +147 -0
  508. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -0
  509. package/mcp-server/dist/tools/youtube/source.d.ts +36 -0
  510. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -0
  511. package/mcp-server/dist/tools/youtube/source.js +85 -0
  512. package/mcp-server/dist/tools/youtube/source.js.map +1 -0
  513. package/mcp-server/dist/tools/youtube/upload.d.ts +53 -0
  514. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -0
  515. package/mcp-server/dist/tools/youtube/upload.js +255 -0
  516. package/mcp-server/dist/tools/youtube/upload.js.map +1 -0
  517. package/mcp-server/dist/tools/youtube.d.ts +12 -0
  518. package/mcp-server/dist/tools/youtube.d.ts.map +1 -0
  519. package/mcp-server/dist/tools/youtube.js +38 -0
  520. package/mcp-server/dist/tools/youtube.js.map +1 -0
  521. package/mcp-server/dist/tui.d.ts +3 -0
  522. package/mcp-server/dist/tui.d.ts.map +1 -0
  523. package/mcp-server/dist/tui.js +806 -0
  524. package/mcp-server/dist/tui.js.map +1 -0
  525. package/mcp-server/dist/types.d.ts +77 -0
  526. package/mcp-server/dist/types.d.ts.map +1 -0
  527. package/mcp-server/dist/types.js +2 -0
  528. package/mcp-server/dist/types.js.map +1 -0
  529. package/mcp-server/package-lock.json +4798 -0
  530. package/mcp-server/package.json +55 -38
  531. package/mcp-server/run.mjs +12 -2
  532. package/mcp-server/src/config.ts +48 -3
  533. package/mcp-server/src/http.ts +296 -93
  534. package/mcp-server/src/index.ts +546 -203
  535. package/mcp-server/src/preload-http.ts +19 -18
  536. package/mcp-server/src/preload.ts +19 -18
  537. package/mcp-server/src/scripts/setup-embeddings.ts +9 -0
  538. package/mcp-server/src/services/assistant-judgments.ts +157 -0
  539. package/mcp-server/src/services/browser-assist-gate.ts +383 -0
  540. package/mcp-server/src/services/browser-assist.ts +267 -0
  541. package/mcp-server/src/services/browser-bench.ts +477 -0
  542. package/mcp-server/src/services/browser-judgments.ts +414 -0
  543. package/mcp-server/src/services/browser-risk.ts +484 -0
  544. package/mcp-server/src/services/categories.ts +36 -19
  545. package/mcp-server/src/services/codex-config-heal.ts +403 -0
  546. package/mcp-server/src/services/desktop-assist-gate.ts +251 -0
  547. package/mcp-server/src/services/desktop-assist.ts +308 -0
  548. package/mcp-server/src/services/desktop-bench.ts +372 -0
  549. package/mcp-server/src/services/desktop-client.ts +76 -0
  550. package/mcp-server/src/services/desktop-judgments.ts +218 -0
  551. package/mcp-server/src/services/desktop-risk.ts +743 -0
  552. package/mcp-server/src/services/edit-stale.ts +299 -0
  553. package/mcp-server/src/services/embedding-service.ts +108 -0
  554. package/mcp-server/src/services/embedding-worker.ts +46 -0
  555. package/mcp-server/src/services/fb-regions.ts +221 -0
  556. package/mcp-server/src/services/file-checksums.ts +26 -9
  557. package/mcp-server/src/services/file-excerpt.ts +59 -0
  558. package/mcp-server/src/services/identity.ts +291 -0
  559. package/mcp-server/src/services/local-embeddings.ts +2 -77
  560. package/mcp-server/src/services/memory-client.ts +23 -0
  561. package/mcp-server/src/services/memory-judge-backfill.ts +462 -0
  562. package/mcp-server/src/services/memory-judgments.ts +901 -0
  563. package/mcp-server/src/services/memory-maintenance.ts +360 -0
  564. package/mcp-server/src/services/memory-retrieval.ts +349 -0
  565. package/mcp-server/src/services/memory-schema.ts +280 -0
  566. package/mcp-server/src/services/memory-sessions.ts +87 -0
  567. package/mcp-server/src/services/memory-triage.ts +182 -0
  568. package/mcp-server/src/services/memory-verification.ts +68 -0
  569. package/mcp-server/src/services/memory-writer.ts +125 -0
  570. package/mcp-server/src/services/neural-interface.ts +1217 -73
  571. package/mcp-server/src/services/profiles.ts +428 -0
  572. package/mcp-server/src/services/secret-gate.ts +52 -0
  573. package/mcp-server/src/services/server-instructions.ts +122 -0
  574. package/mcp-server/src/services/sqlite.ts +1456 -823
  575. package/mcp-server/src/services/typesafe-bench.ts +247 -0
  576. package/mcp-server/src/services/typesafe-config.ts +790 -0
  577. package/mcp-server/src/services/typesafe.ts +390 -0
  578. package/mcp-server/src/services/vector-cache.ts +255 -0
  579. package/mcp-server/src/services/whiteboard-geometry.ts +711 -0
  580. package/mcp-server/src/tools/agents.ts +539 -0
  581. package/mcp-server/src/tools/bluesky.ts +1186 -0
  582. package/mcp-server/src/tools/browser-advanced.ts +15 -6
  583. package/mcp-server/src/tools/browser-batch.ts +178 -0
  584. package/mcp-server/src/tools/browser-cheatsheet.ts +155 -0
  585. package/mcp-server/src/tools/browser-interact.ts +362 -255
  586. package/mcp-server/src/tools/browser-navigate.ts +164 -77
  587. package/mcp-server/src/tools/browser-observe.ts +2222 -1330
  588. package/mcp-server/src/tools/browser.ts +181 -107
  589. package/mcp-server/src/tools/card.ts +7 -5
  590. package/mcp-server/src/tools/choice.ts +103 -0
  591. package/mcp-server/src/tools/computer.ts +190 -0
  592. package/mcp-server/src/tools/discord.ts +10 -23
  593. package/mcp-server/src/tools/fb-groups.ts +387 -0
  594. package/mcp-server/src/tools/forget.ts +1 -1
  595. package/mcp-server/src/tools/git.ts +3 -1
  596. package/mcp-server/src/tools/gsc/experience.ts +440 -0
  597. package/mcp-server/src/tools/gsc/helpers.ts +288 -0
  598. package/mcp-server/src/tools/gsc/indexing.ts +495 -0
  599. package/mcp-server/src/tools/gsc/inspect.ts +391 -0
  600. package/mcp-server/src/tools/gsc/navigate.ts +236 -0
  601. package/mcp-server/src/tools/gsc/performance.ts +352 -0
  602. package/mcp-server/src/tools/gsc/settings.ts +564 -0
  603. package/mcp-server/src/tools/gsc.ts +95 -0
  604. package/mcp-server/src/tools/image.ts +3 -1
  605. package/mcp-server/src/tools/leonardo-browser-tools.ts +47 -37
  606. package/mcp-server/src/tools/leonardo.ts +7 -5
  607. package/mcp-server/src/tools/loop.ts +118 -25
  608. package/mcp-server/src/tools/memories.ts +65 -5
  609. package/mcp-server/src/tools/morelogin.ts +81 -0
  610. package/mcp-server/src/tools/profile.ts +122 -0
  611. package/mcp-server/src/tools/recall.ts +105 -261
  612. package/mcp-server/src/tools/reflect.ts +171 -145
  613. package/mcp-server/src/tools/remember.ts +223 -115
  614. package/mcp-server/src/tools/style-guide-tools.ts +250 -0
  615. package/mcp-server/src/tools/style-guide.ts +16 -0
  616. package/mcp-server/src/tools/sync.ts +66 -9
  617. package/mcp-server/src/tools/tictactoe.ts +3 -1
  618. package/mcp-server/src/tools/utils.ts +22 -0
  619. package/mcp-server/src/tools/whiteboard-format.ts +394 -0
  620. package/mcp-server/src/tools/whiteboard-tools.ts +191 -183
  621. package/mcp-server/src/tools/whiteboard.ts +7 -5
  622. package/mcp-server/src/tools/youtube/analytics.ts +106 -0
  623. package/mcp-server/src/tools/youtube/dedup.ts +57 -0
  624. package/mcp-server/src/tools/youtube/download.ts +41 -0
  625. package/mcp-server/src/tools/youtube/helpers.ts +183 -0
  626. package/mcp-server/src/tools/youtube/media.ts +109 -0
  627. package/mcp-server/src/tools/youtube/metadata.ts +112 -0
  628. package/mcp-server/src/tools/youtube/navigate.ts +81 -0
  629. package/mcp-server/src/tools/youtube/playlist.ts +134 -0
  630. package/mcp-server/src/tools/youtube/schedule.ts +158 -0
  631. package/mcp-server/src/tools/youtube/source.ts +101 -0
  632. package/mcp-server/src/tools/youtube/upload.ts +296 -0
  633. package/mcp-server/src/tools/youtube.ts +47 -0
  634. package/mcp-server/src/tui.ts +8 -9
  635. package/neural-interface/games/TicTacToe/1.svg +1 -0
  636. package/neural-interface/games/TicTacToe/2.svg +1 -0
  637. package/neural-interface/games/TicTacToe/3.svg +1 -0
  638. package/neural-interface/games/TicTacToe/4.svg +1 -0
  639. package/neural-interface/games/TicTacToe/5.svg +1 -0
  640. package/neural-interface/games/TicTacToe/6.svg +1 -0
  641. package/neural-interface/games/TicTacToe/7.svg +1 -0
  642. package/neural-interface/games/TicTacToe/8.svg +1 -0
  643. package/neural-interface/games/TicTacToe/9.svg +1 -0
  644. package/neural-interface/games/TicTacToe/Board.svg +1 -0
  645. package/neural-interface/games/TicTacToe/Circle.svg +1 -0
  646. package/neural-interface/games/TicTacToe/Cross.svg +1 -0
  647. package/neural-interface/i18n/en.json +6983 -0
  648. package/neural-interface/i18n/pt-BR.json +6987 -0
  649. package/neural-interface/lib/assistant-api.js +1005 -0
  650. package/neural-interface/lib/assistant-attachments.js +121 -0
  651. package/neural-interface/lib/assistant-brains/claude.js +207 -0
  652. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +43 -0
  653. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +56 -0
  654. package/neural-interface/lib/assistant-brains/codex.js +213 -0
  655. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +47 -0
  656. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +62 -0
  657. package/neural-interface/lib/assistant-brains/opencode.js +320 -0
  658. package/neural-interface/lib/assistant-budget.js +318 -0
  659. package/neural-interface/lib/assistant-catalog.js +731 -0
  660. package/neural-interface/lib/assistant-clarify.js +664 -0
  661. package/neural-interface/lib/assistant-config.js +232 -0
  662. package/neural-interface/lib/assistant-dispatch.js +2744 -0
  663. package/neural-interface/lib/assistant-envelope.js +579 -0
  664. package/neural-interface/lib/assistant-evidence.js +236 -0
  665. package/neural-interface/lib/assistant-hidden-models.js +272 -0
  666. package/neural-interface/lib/assistant-jev.js +117 -0
  667. package/neural-interface/lib/assistant-judgments.js +111 -0
  668. package/neural-interface/lib/assistant-media.js +335 -0
  669. package/neural-interface/lib/assistant-memory.js +398 -0
  670. package/neural-interface/lib/assistant-persona.js +444 -0
  671. package/neural-interface/lib/assistant-plan-permissions.js +448 -0
  672. package/neural-interface/lib/assistant-playbooks/design.md +87 -0
  673. package/neural-interface/lib/assistant-playbooks.js +72 -0
  674. package/neural-interface/lib/assistant-pricing.js +159 -0
  675. package/neural-interface/lib/assistant-route-gate-codex.js +163 -0
  676. package/neural-interface/lib/assistant-route-gate.js +212 -0
  677. package/neural-interface/lib/assistant-router.js +1324 -0
  678. package/neural-interface/lib/assistant-runtime.js +3337 -0
  679. package/neural-interface/lib/assistant-task-prompt.js +472 -0
  680. package/neural-interface/lib/assistant-usage.js +1688 -0
  681. package/neural-interface/lib/augmented-path.js +50 -0
  682. package/neural-interface/lib/automation-storage-migration.js +54 -0
  683. package/neural-interface/lib/backup-service.js +851 -0
  684. package/neural-interface/lib/backup-zip-reader.js +262 -0
  685. package/neural-interface/lib/browser-assist-api.js +41 -0
  686. package/neural-interface/lib/browser-console.js +176 -0
  687. package/neural-interface/lib/browser-execution.js +241 -0
  688. package/neural-interface/lib/browser-extraction.js +191 -0
  689. package/neural-interface/lib/browser-screenshot.js +399 -0
  690. package/neural-interface/lib/browser-semantic-context.js +639 -0
  691. package/neural-interface/lib/browser-snapshots.js +192 -0
  692. package/neural-interface/lib/browser-tab-recovery.js +119 -0
  693. package/neural-interface/lib/browser-targets.js +70 -0
  694. package/neural-interface/lib/browser-tool-policy.js +926 -0
  695. package/neural-interface/lib/claude-accounts.js +230 -0
  696. package/neural-interface/lib/claude-agent-bridge.js +3296 -0
  697. package/neural-interface/lib/claude-bypass-policy.js +99 -0
  698. package/neural-interface/lib/claude-history.js +429 -0
  699. package/neural-interface/lib/claude-model-catalog.js +483 -0
  700. package/neural-interface/lib/claude-panel-requests.js +165 -0
  701. package/neural-interface/lib/claude-panel-session.js +272 -0
  702. package/neural-interface/lib/claude-permission-rules.js +153 -0
  703. package/neural-interface/lib/claude-session-cleanup.js +71 -0
  704. package/neural-interface/lib/claude-session-list.js +82 -0
  705. package/neural-interface/lib/claude-session-ops.js +140 -0
  706. package/neural-interface/lib/claude-settings-view.js +51 -0
  707. package/neural-interface/lib/claude-skin-connect.js +79 -0
  708. package/neural-interface/lib/claude-stall-policy.js +7 -0
  709. package/neural-interface/lib/claude-temporary.js +435 -0
  710. package/neural-interface/lib/cli-update-planner.js +312 -0
  711. package/neural-interface/lib/codex-capabilities.d.ts +41 -0
  712. package/neural-interface/lib/codex-capabilities.js +148 -0
  713. package/neural-interface/lib/codex-collaboration-mode.js +17 -0
  714. package/neural-interface/lib/codex-compat-rpc.js +241 -0
  715. package/neural-interface/lib/codex-mcp-approvals.js +56 -0
  716. package/neural-interface/lib/codex-mcp-apps.js +47 -0
  717. package/neural-interface/lib/codex-model-context.js +202 -0
  718. package/neural-interface/lib/codex-plan-store.js +71 -0
  719. package/neural-interface/lib/codex-request-journal.js +242 -0
  720. package/neural-interface/lib/codex-runtime-path.js +213 -0
  721. package/neural-interface/lib/codex-session-catalog.js +231 -0
  722. package/neural-interface/lib/codex-session-settings.js +46 -0
  723. package/neural-interface/lib/codex-sidepanel-permissions.js +110 -0
  724. package/neural-interface/lib/codex-thread-history.js +165 -0
  725. package/neural-interface/lib/codex-user-verification.js +34 -0
  726. package/neural-interface/lib/codex-writer-lifecycle.js +152 -0
  727. package/neural-interface/lib/confined-fs.js +256 -0
  728. package/neural-interface/lib/db.js +922 -0
  729. package/neural-interface/lib/design-md.js +9 -0
  730. package/neural-interface/lib/desktop/api.js +92 -0
  731. package/neural-interface/lib/desktop/audit.js +62 -0
  732. package/neural-interface/lib/desktop/build.js +423 -0
  733. package/neural-interface/lib/desktop/config.js +606 -0
  734. package/neural-interface/lib/desktop/coords.js +76 -0
  735. package/neural-interface/lib/desktop/fake-helper.js +1192 -0
  736. package/neural-interface/lib/desktop/frames.js +77 -0
  737. package/neural-interface/lib/desktop/grants.js +84 -0
  738. package/neural-interface/lib/desktop/guards.js +170 -0
  739. package/neural-interface/lib/desktop/helper/SynabunDesktop.swift +3056 -0
  740. package/neural-interface/lib/desktop/lease.js +51 -0
  741. package/neural-interface/lib/desktop/manager.js +545 -0
  742. package/neural-interface/lib/desktop/press-contexts.js +103 -0
  743. package/neural-interface/lib/desktop/protocol.js +495 -0
  744. package/neural-interface/lib/desktop/service.js +1202 -0
  745. package/neural-interface/lib/effort-levels.js +148 -0
  746. package/neural-interface/lib/event-loop-monitor.js +67 -0
  747. package/neural-interface/lib/exec-loop-command.js +209 -0
  748. package/neural-interface/lib/folder-picker.ps1 +77 -0
  749. package/neural-interface/lib/http-guards.js +287 -0
  750. package/neural-interface/lib/jsonl-lines.js +94 -0
  751. package/neural-interface/lib/loop-logger.js +127 -0
  752. package/neural-interface/lib/mcp-client-config.js +133 -0
  753. package/neural-interface/lib/mcp-installer.js +487 -0
  754. package/neural-interface/lib/mcp-profile-refresh-coordinator.js +78 -0
  755. package/neural-interface/lib/mcp-profile-servers.js +120 -0
  756. package/neural-interface/lib/memo-cache.js +84 -0
  757. package/neural-interface/lib/memory-api.js +758 -0
  758. package/neural-interface/lib/memory-map-api.js +1150 -0
  759. package/neural-interface/lib/memory-map-layout.js +872 -0
  760. package/neural-interface/lib/memory-map-worker.js +165 -0
  761. package/neural-interface/lib/memory-session-capture.js +81 -0
  762. package/neural-interface/lib/memory-timers.js +62 -0
  763. package/neural-interface/lib/morelogin.js +301 -0
  764. package/neural-interface/lib/native-binary-runtime.js +650 -0
  765. package/neural-interface/lib/native-loop-goal.js +33 -0
  766. package/neural-interface/lib/native-loop-providers.js +1016 -0
  767. package/neural-interface/lib/native-loop-runtime.js +747 -0
  768. package/neural-interface/lib/opencode-hidden-models.js +113 -0
  769. package/neural-interface/lib/opencode-history.js +253 -0
  770. package/neural-interface/lib/opencode-runtime-config.js +58 -0
  771. package/neural-interface/lib/opencode-v2-client.js +486 -0
  772. package/neural-interface/lib/opencode-v2-ws-requests.js +955 -0
  773. package/neural-interface/lib/path-confine.js +213 -0
  774. package/neural-interface/lib/plugin-installer.js +264 -0
  775. package/neural-interface/lib/project-storage.js +766 -0
  776. package/neural-interface/lib/pty-host/core.js +603 -0
  777. package/neural-interface/lib/pty-host/flow.js +43 -0
  778. package/neural-interface/lib/pty-host/host.js +47 -0
  779. package/neural-interface/lib/pty-host/manager.js +360 -0
  780. package/neural-interface/lib/pty-host/protocol.js +81 -0
  781. package/neural-interface/lib/pty-host/snapshot.js +133 -0
  782. package/neural-interface/lib/remote-policy.js +582 -0
  783. package/neural-interface/lib/rulesets/api.js +175 -0
  784. package/neural-interface/lib/rulesets/fs-safe.js +245 -0
  785. package/neural-interface/lib/rulesets/installer.js +1453 -0
  786. package/neural-interface/lib/rulesets/json-edit.js +186 -0
  787. package/neural-interface/lib/rulesets/lock.js +170 -0
  788. package/neural-interface/lib/rulesets/managed-text.js +314 -0
  789. package/neural-interface/lib/rulesets/normalise.js +24 -0
  790. package/neural-interface/lib/rulesets/render.js +84 -0
  791. package/neural-interface/lib/schedule-launch-intent.js +40 -0
  792. package/neural-interface/lib/session-cache-builder.js +524 -0
  793. package/neural-interface/lib/session-chunker.js +344 -0
  794. package/neural-interface/lib/session-indexer.js +327 -0
  795. package/neural-interface/lib/session-title-generator.js +227 -0
  796. package/neural-interface/lib/skill-prompt-bridge.js +11 -0
  797. package/neural-interface/lib/style-guide/api.js +375 -0
  798. package/neural-interface/lib/style-guide/color.js +352 -0
  799. package/neural-interface/lib/style-guide/export-css.js +99 -0
  800. package/neural-interface/lib/style-guide/export-dtcg.js +209 -0
  801. package/neural-interface/lib/style-guide/export-tailwind.js +102 -0
  802. package/neural-interface/lib/style-guide/fonts.json +227 -0
  803. package/neural-interface/lib/style-guide/import.js +1268 -0
  804. package/neural-interface/lib/style-guide/pointers.js +103 -0
  805. package/neural-interface/lib/style-guide/presets.js +232 -0
  806. package/neural-interface/lib/style-guide/render-design-md.js +319 -0
  807. package/neural-interface/lib/style-guide/schema.js +848 -0
  808. package/neural-interface/lib/style-guide/security.js +43 -0
  809. package/neural-interface/lib/style-guide/store.js +491 -0
  810. package/neural-interface/lib/style-guide/summary.js +106 -0
  811. package/neural-interface/lib/style-guide/tokens.js +170 -0
  812. package/neural-interface/lib/synabun-update-plan.js +305 -0
  813. package/neural-interface/lib/synabun-version.js +179 -0
  814. package/neural-interface/lib/system-restore.js +99 -0
  815. package/neural-interface/lib/terminal-env.js +86 -0
  816. package/neural-interface/lib/ui-blob-store.js +106 -0
  817. package/neural-interface/lib/vector-cache.js +2 -0
  818. package/neural-interface/lib/virtual-socket.js +60 -0
  819. package/neural-interface/lib/whatsapp/api.js +146 -0
  820. package/neural-interface/lib/whatsapp/auth-store.js +389 -0
  821. package/neural-interface/lib/whatsapp/baileys-adapter.js +457 -0
  822. package/neural-interface/lib/whatsapp/brain.js +128 -0
  823. package/neural-interface/lib/whatsapp/bridge.js +1499 -0
  824. package/neural-interface/lib/whatsapp/cards.js +519 -0
  825. package/neural-interface/lib/whatsapp/commands.js +92 -0
  826. package/neural-interface/lib/whatsapp/config.js +291 -0
  827. package/neural-interface/lib/whatsapp/connector/entry.mjs +25 -0
  828. package/neural-interface/lib/whatsapp/connector/manifest.json +6 -0
  829. package/neural-interface/lib/whatsapp/connector/npm-shrinkwrap.json +717 -0
  830. package/neural-interface/lib/whatsapp/connector/package.json +8 -0
  831. package/neural-interface/lib/whatsapp/fake-baileys.js +444 -0
  832. package/neural-interface/lib/whatsapp/format.js +552 -0
  833. package/neural-interface/lib/whatsapp/host-core.js +1225 -0
  834. package/neural-interface/lib/whatsapp/host.js +119 -0
  835. package/neural-interface/lib/whatsapp/identity.js +288 -0
  836. package/neural-interface/lib/whatsapp/inbound.js +149 -0
  837. package/neural-interface/lib/whatsapp/installer.js +562 -0
  838. package/neural-interface/lib/whatsapp/manager.js +638 -0
  839. package/neural-interface/lib/whatsapp/paths.js +81 -0
  840. package/neural-interface/lib/whatsapp/protocol.js +327 -0
  841. package/neural-interface/lib/whatsapp/qr-svg.js +57 -0
  842. package/neural-interface/lib/whatsapp/redact.js +130 -0
  843. package/neural-interface/lib/whatsapp/service.js +1305 -0
  844. package/neural-interface/lib/whatsapp/vendor/qrcodegen.js +848 -0
  845. package/neural-interface/package-lock.json +4682 -0
  846. package/neural-interface/package.json +58 -27
  847. package/neural-interface/public/apple-touch-icon.png +0 -0
  848. package/neural-interface/public/category-logos/synabun.png +0 -0
  849. package/neural-interface/public/claude.svg +1 -0
  850. package/neural-interface/public/favicon-16x16.png +0 -0
  851. package/neural-interface/public/favicon-32x32.png +0 -0
  852. package/neural-interface/public/icon-192.png +0 -0
  853. package/neural-interface/public/icon-512.png +0 -0
  854. package/neural-interface/public/index.html +32 -182
  855. package/neural-interface/public/index2d.html +2 -2
  856. package/neural-interface/public/logo-synabun.png +0 -0
  857. package/neural-interface/public/logoHD.png +0 -0
  858. package/neural-interface/public/mcp.svg +4 -0
  859. package/neural-interface/public/offline.html +335 -299
  860. package/neural-interface/public/onboarding.html +692 -155
  861. package/neural-interface/public/opencode-logo-dark-square.svg +1 -0
  862. package/neural-interface/public/shared/agent-runtime-options.js +596 -0
  863. package/neural-interface/public/shared/api.js +339 -28
  864. package/neural-interface/public/shared/assistant/asst-accounts.js +318 -0
  865. package/neural-interface/public/shared/assistant/asst-agents-dock.js +296 -0
  866. package/neural-interface/public/shared/assistant/asst-api.js +270 -0
  867. package/neural-interface/public/shared/assistant/asst-brain-picker.js +744 -0
  868. package/neural-interface/public/shared/assistant/asst-budget.js +333 -0
  869. package/neural-interface/public/shared/assistant/asst-composer.js +656 -0
  870. package/neural-interface/public/shared/assistant/asst-computer.js +803 -0
  871. package/neural-interface/public/shared/assistant/asst-control.js +1018 -0
  872. package/neural-interface/public/shared/assistant/asst-hosts.js +262 -0
  873. package/neural-interface/public/shared/assistant/asst-mascot.js +311 -0
  874. package/neural-interface/public/shared/assistant/asst-menu.js +375 -0
  875. package/neural-interface/public/shared/assistant/asst-panel.js +1845 -0
  876. package/neural-interface/public/shared/assistant/asst-rack-styles.js +589 -0
  877. package/neural-interface/public/shared/assistant/asst-render.js +3296 -0
  878. package/neural-interface/public/shared/assistant/asst-route.js +1653 -0
  879. package/neural-interface/public/shared/assistant/asst-roving.js +75 -0
  880. package/neural-interface/public/shared/assistant/asst-sanitize.js +117 -0
  881. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +488 -0
  882. package/neural-interface/public/shared/assistant/asst-sidepanel.js +675 -0
  883. package/neural-interface/public/shared/assistant/asst-slash.js +258 -0
  884. package/neural-interface/public/shared/assistant/asst-state.js +727 -0
  885. package/neural-interface/public/shared/assistant/asst-styles.js +1684 -0
  886. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +1017 -0
  887. package/neural-interface/public/shared/assistant/asst-usage.js +444 -0
  888. package/neural-interface/public/shared/assistant/asst-ws.js +175 -0
  889. package/neural-interface/public/shared/automation-context.js +75 -0
  890. package/neural-interface/public/shared/blob-store.js +99 -0
  891. package/neural-interface/public/shared/cdx/cdx-capabilities.js +118 -0
  892. package/neural-interface/public/shared/cdx/cdx-cards.js +37 -0
  893. package/neural-interface/public/shared/cdx/cdx-commands.js +171 -0
  894. package/neural-interface/public/shared/cdx/cdx-context-menu.js +402 -0
  895. package/neural-interface/public/shared/cdx/cdx-context-model.js +220 -0
  896. package/neural-interface/public/shared/cdx/cdx-features.js +408 -0
  897. package/neural-interface/public/shared/cdx/cdx-icons.js +89 -0
  898. package/neural-interface/public/shared/cdx/cdx-mcp-app-host.js +414 -0
  899. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.html +6 -0
  900. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.js +56 -0
  901. package/neural-interface/public/shared/cdx/cdx-mcp-app.js +178 -0
  902. package/neural-interface/public/shared/cdx/cdx-model-catalog.js +120 -0
  903. package/neural-interface/public/shared/cdx/cdx-output-model.js +261 -0
  904. package/neural-interface/public/shared/cdx/cdx-output.js +382 -0
  905. package/neural-interface/public/shared/cdx/cdx-panel.js +1372 -0
  906. package/neural-interface/public/shared/cdx/cdx-plan.js +266 -0
  907. package/neural-interface/public/shared/cdx/cdx-protocol.js +682 -0
  908. package/neural-interface/public/shared/cdx/cdx-render.js +3381 -0
  909. package/neural-interface/public/shared/cdx/cdx-requests.js +1136 -0
  910. package/neural-interface/public/shared/cdx/cdx-styles.js +3251 -0
  911. package/neural-interface/public/shared/cdx/cdx-tabs.js +7992 -0
  912. package/neural-interface/public/shared/cdx/cdx-ws.js +363 -0
  913. package/neural-interface/public/shared/cli-status.js +169 -0
  914. package/neural-interface/public/shared/constants.js +22 -5
  915. package/neural-interface/public/shared/cp/cp-agents.js +186 -0
  916. package/neural-interface/public/shared/cp/cp-bash.js +252 -0
  917. package/neural-interface/public/shared/cp/cp-compose.js +159 -0
  918. package/neural-interface/public/shared/cp/cp-context-menu.js +309 -0
  919. package/neural-interface/public/shared/cp/cp-context-model.js +157 -0
  920. package/neural-interface/public/shared/cp/cp-context-window.js +80 -0
  921. package/neural-interface/public/shared/cp/cp-ctx.js +11 -0
  922. package/neural-interface/public/shared/cp/cp-diff.js +255 -0
  923. package/neural-interface/public/shared/cp/cp-event-rows.js +637 -0
  924. package/neural-interface/public/shared/cp/cp-events.js +846 -0
  925. package/neural-interface/public/shared/cp/cp-markdown.js +104 -0
  926. package/neural-interface/public/shared/cp/cp-permission-model.js +905 -0
  927. package/neural-interface/public/shared/cp/cp-permissions.js +626 -0
  928. package/neural-interface/public/shared/cp/cp-rehydrate.js +113 -0
  929. package/neural-interface/public/shared/cp/cp-restore.js +224 -0
  930. package/neural-interface/public/shared/cp/cp-session-model.js +338 -0
  931. package/neural-interface/public/shared/cp/cp-session-settings.js +254 -0
  932. package/neural-interface/public/shared/cp/cp-sessions.js +227 -0
  933. package/neural-interface/public/shared/cp/cp-statusline.js +153 -0
  934. package/neural-interface/public/shared/cp/cp-styles.js +349 -0
  935. package/neural-interface/public/shared/cp/cp-tasks-model.js +282 -0
  936. package/neural-interface/public/shared/cp/cp-tasks.js +107 -0
  937. package/neural-interface/public/shared/cp/cp-temporary-view.js +56 -0
  938. package/neural-interface/public/shared/cp/cp-temporary.js +231 -0
  939. package/neural-interface/public/shared/cp/cp-tool-cards.js +326 -0
  940. package/neural-interface/public/shared/cp/cp-tool-results.js +618 -0
  941. package/neural-interface/public/shared/cp/cp-usage-model.js +124 -0
  942. package/neural-interface/public/shared/graph-activity.js +68 -0
  943. package/neural-interface/public/shared/html-shell.js +107 -12
  944. package/neural-interface/public/shared/i18n.js +132 -34
  945. package/neural-interface/public/shared/node-positions-store.js +44 -0
  946. package/neural-interface/public/shared/ocp-hidden-models.js +116 -0
  947. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +355 -0
  948. package/neural-interface/public/shared/ocp-v2/ocp-v2-autoaccept-button.js +35 -0
  949. package/neural-interface/public/shared/ocp-v2/ocp-v2-automation-ownership.js +72 -0
  950. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +280 -0
  951. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +67 -0
  952. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +179 -0
  953. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes.js +164 -0
  954. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +725 -0
  955. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +75 -0
  956. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +1204 -0
  957. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm-logic.js +117 -0
  958. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm.js +59 -0
  959. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-gauge.js +252 -0
  960. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +478 -0
  961. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +179 -0
  962. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +233 -0
  963. package/neural-interface/public/shared/ocp-v2/ocp-v2-icons.js +30 -0
  964. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +1065 -0
  965. package/neural-interface/public/shared/ocp-v2/ocp-v2-mention-hints.js +182 -0
  966. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +655 -0
  967. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +2636 -0
  968. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +601 -0
  969. package/neural-interface/public/shared/ocp-v2/ocp-v2-profile-inheritance.js +78 -0
  970. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +649 -0
  971. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +35 -0
  972. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +357 -0
  973. package/neural-interface/public/shared/ocp-v2/ocp-v2-render-logic.js +189 -0
  974. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1869 -0
  975. package/neural-interface/public/shared/ocp-v2/ocp-v2-select.js +42 -0
  976. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +117 -0
  977. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +1714 -0
  978. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +468 -0
  979. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-widgets.js +63 -0
  980. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +366 -0
  981. package/neural-interface/public/shared/ocp-v2/ocp-v2-settings-link.js +19 -0
  982. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +343 -0
  983. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +746 -0
  984. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +347 -0
  985. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +338 -0
  986. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +3543 -0
  987. package/neural-interface/public/shared/ocp-v2/ocp-v2-subagents-logic.js +482 -0
  988. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools-logic.js +351 -0
  989. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools.js +168 -0
  990. package/neural-interface/public/shared/ocp-v2/ocp-v2-variantpicker.js +315 -0
  991. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +545 -0
  992. package/neural-interface/public/shared/provider-icons.js +30 -0
  993. package/neural-interface/public/shared/session-title.js +100 -0
  994. package/neural-interface/public/shared/settings/settings-ia.js +389 -0
  995. package/neural-interface/public/shared/settings/settings-kit.js +234 -0
  996. package/neural-interface/public/shared/settings/settings-search.js +463 -0
  997. package/neural-interface/public/shared/settings/settings-shell.js +570 -0
  998. package/neural-interface/public/shared/state.js +5 -0
  999. package/neural-interface/public/shared/storage.js +50 -7
  1000. package/neural-interface/public/shared/styleguide/sg-agents.js +42 -0
  1001. package/neural-interface/public/shared/styleguide/sg-brand.js +4 -0
  1002. package/neural-interface/public/shared/styleguide/sg-color-client.js +388 -0
  1003. package/neural-interface/public/shared/styleguide/sg-colors.js +148 -0
  1004. package/neural-interface/public/shared/styleguide/sg-components.js +35 -0
  1005. package/neural-interface/public/shared/styleguide/sg-history.js +41 -0
  1006. package/neural-interface/public/shared/styleguide/sg-icons-logo.js +38 -0
  1007. package/neural-interface/public/shared/styleguide/sg-imagery.js +4 -0
  1008. package/neural-interface/public/shared/styleguide/sg-import-export.js +47 -0
  1009. package/neural-interface/public/shared/styleguide/sg-kit.js +281 -0
  1010. package/neural-interface/public/shared/styleguide/sg-labels.js +318 -0
  1011. package/neural-interface/public/shared/styleguide/sg-layout.js +4 -0
  1012. package/neural-interface/public/shared/styleguide/sg-motion.js +5 -0
  1013. package/neural-interface/public/shared/styleguide/sg-panel.js +229 -0
  1014. package/neural-interface/public/shared/styleguide/sg-preview.js +138 -0
  1015. package/neural-interface/public/shared/styleguide/sg-rules.js +9 -0
  1016. package/neural-interface/public/shared/styleguide/sg-shape.js +24 -0
  1017. package/neural-interface/public/shared/styleguide/sg-state.js +132 -0
  1018. package/neural-interface/public/shared/styleguide/sg-typography.js +124 -0
  1019. package/neural-interface/public/shared/styles.css +7883 -1155
  1020. package/neural-interface/public/shared/synabun-mascot.js +1625 -0
  1021. package/neural-interface/public/shared/synabun-ticker.js +376 -0
  1022. package/neural-interface/public/shared/term-renderer.js +343 -0
  1023. package/neural-interface/public/shared/ui-assistant-panel.js +10 -0
  1024. package/neural-interface/public/shared/ui-assistant.js +77 -0
  1025. package/neural-interface/public/shared/ui-automation-studio.js +5105 -3573
  1026. package/neural-interface/public/shared/ui-claude-panel.js +11685 -6333
  1027. package/neural-interface/public/shared/ui-codex-panel.js +12 -0
  1028. package/neural-interface/public/shared/ui-cost-widget.js +55 -34
  1029. package/neural-interface/public/shared/ui-detail.js +77 -14
  1030. package/neural-interface/public/shared/ui-explorer.js +360 -181
  1031. package/neural-interface/public/shared/ui-file-explorer.js +485 -107
  1032. package/neural-interface/public/shared/ui-help.js +2 -2
  1033. package/neural-interface/public/shared/ui-image-gallery.js +45 -21
  1034. package/neural-interface/public/shared/ui-judgments.js +1346 -0
  1035. package/neural-interface/public/shared/ui-keybinds.js +3 -2
  1036. package/neural-interface/public/shared/ui-link.js +105 -51
  1037. package/neural-interface/public/shared/ui-loading.js +4 -4
  1038. package/neural-interface/public/shared/ui-memory-maintenance.js +111 -0
  1039. package/neural-interface/public/shared/ui-menubar.js +89 -4
  1040. package/neural-interface/public/shared/ui-native-loop-router-state.js +94 -0
  1041. package/neural-interface/public/shared/ui-native-loop-router.js +493 -0
  1042. package/neural-interface/public/shared/ui-native-window-id.js +7 -0
  1043. package/neural-interface/public/shared/ui-navbar.js +357 -222
  1044. package/neural-interface/public/shared/ui-notifications.js +58 -12
  1045. package/neural-interface/public/shared/ui-opencode-panel-v2.js +17 -0
  1046. package/neural-interface/public/shared/ui-panels.js +15 -7
  1047. package/neural-interface/public/shared/ui-resume.js +823 -653
  1048. package/neural-interface/public/shared/ui-schedule-queue.js +172 -0
  1049. package/neural-interface/public/shared/ui-schedules-studio.js +1882 -0
  1050. package/neural-interface/public/shared/ui-scroll-follow.js +194 -0
  1051. package/neural-interface/public/shared/ui-sessions.js +789 -34
  1052. package/neural-interface/public/shared/ui-settings.js +5793 -2190
  1053. package/neural-interface/public/shared/ui-sidepanel-layout.js +109 -0
  1054. package/neural-interface/public/shared/ui-sidepanel-runtime.js +19 -0
  1055. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +40 -0
  1056. package/neural-interface/public/shared/ui-sidepanel-sessions.js +221 -0
  1057. package/neural-interface/public/shared/ui-sidepanel-state.js +131 -0
  1058. package/neural-interface/public/shared/ui-sidepanel-tray.js +547 -0
  1059. package/neural-interface/public/shared/ui-sidepanel-windows.js +387 -0
  1060. package/neural-interface/public/shared/ui-skills.js +18 -32
  1061. package/neural-interface/public/shared/ui-styleguide.js +35 -0
  1062. package/neural-interface/public/shared/ui-sync.js +87 -0
  1063. package/neural-interface/public/shared/ui-terminal.js +7877 -6385
  1064. package/neural-interface/public/shared/ui-tool-updates.js +292 -0
  1065. package/neural-interface/public/shared/ui-tooltip.js +156 -15
  1066. package/neural-interface/public/shared/ui-tutorial-draw.js +119 -683
  1067. package/neural-interface/public/shared/ui-tutorial-layout.js +135 -0
  1068. package/neural-interface/public/shared/ui-tutorial-steps.js +59 -2209
  1069. package/neural-interface/public/shared/ui-tutorial.css +102 -0
  1070. package/neural-interface/public/shared/ui-tutorial.js +557 -1076
  1071. package/neural-interface/public/shared/ui-update.js +420 -68
  1072. package/neural-interface/public/shared/ui-whatsapp.js +941 -0
  1073. package/neural-interface/public/shared/ui-whiteboard.js +1076 -233
  1074. package/neural-interface/public/shared/ui-workspaces.js +2 -1
  1075. package/neural-interface/public/shared/utils.js +58 -0
  1076. package/neural-interface/public/shared/vterm-buffer.js +15 -5
  1077. package/neural-interface/public/shared/whatsapp/wa-phone.js +65 -0
  1078. package/neural-interface/public/shared/whatsapp/wa-view.js +411 -0
  1079. package/neural-interface/public/sidepanel-session.html +18 -0
  1080. package/neural-interface/public/sw.js +8 -2
  1081. package/neural-interface/public/synabun.png +0 -0
  1082. package/neural-interface/public/variant/2d/graph.js +1707 -1635
  1083. package/neural-interface/public/variant/2d/lasso.js +2 -1
  1084. package/neural-interface/public/variant/2d/layout.js +595 -594
  1085. package/neural-interface/public/variant/2d/main.js +556 -521
  1086. package/neural-interface/public/variant/2d/settings-gfx.js +18 -24
  1087. package/neural-interface/public/variant/3d/main.js +516 -500
  1088. package/neural-interface/public/variant/3d/map-controls.js +144 -0
  1089. package/neural-interface/public/variant/3d/map-data.js +251 -0
  1090. package/neural-interface/public/variant/3d/map-labels.js +241 -0
  1091. package/neural-interface/public/variant/3d/map-pick.js +90 -0
  1092. package/neural-interface/public/variant/3d/map-renderer.js +521 -0
  1093. package/neural-interface/public/variant/3d/map-shaders.js +158 -0
  1094. package/neural-interface/public/variant/3d/map-view.js +618 -0
  1095. package/neural-interface/public/vendor/three/manifest.json +3 -0
  1096. package/neural-interface/public/vendor/three/three-0.169.0.min.js +3844 -0
  1097. package/neural-interface/public/vendor/xterm/manifest.json +3 -0
  1098. package/neural-interface/public/vendor/xterm/xterm-6.0.0.css +285 -0
  1099. package/neural-interface/public/vendor/xterm/xterm-6.0.0.min.js +192 -0
  1100. package/neural-interface/scripts/build-vendor.mjs +64 -0
  1101. package/neural-interface/scripts/codex-protocol-fixture.mjs +83 -0
  1102. package/neural-interface/scripts/rebuild-pty.js +37 -23
  1103. package/neural-interface/scripts/vendor-three-entry.js +24 -0
  1104. package/neural-interface/scripts/vendor-xterm-entry.js +8 -0
  1105. package/neural-interface/server.js +33948 -15000
  1106. package/neural-interface/skins/default/skin.css +90 -0
  1107. package/neural-interface/skins/default/skin.json +8 -0
  1108. package/neural-interface/templates/rulesets/README.md +9 -0
  1109. package/neural-interface/templates/rulesets/claude.md +3 -0
  1110. package/neural-interface/templates/rulesets/codex.md +2 -0
  1111. package/neural-interface/templates/rulesets/coexistence.md +6 -0
  1112. package/neural-interface/templates/rulesets/core.md +26 -0
  1113. package/neural-interface/templates/rulesets/cursor.md +2 -0
  1114. package/neural-interface/templates/rulesets/gemini.md +2 -0
  1115. package/neural-interface/templates/rulesets/legacy-hashes.json +227 -0
  1116. package/neural-interface/templates/rulesets/manifest.json +12 -0
  1117. package/neural-interface/templates/rulesets/opencode.md +2 -0
  1118. package/package.json +119 -53
  1119. package/postinstall.js +125 -26
  1120. package/preuninstall.js +187 -0
  1121. package/scripts/audit-claude-hook-usage.mjs +12 -0
  1122. package/scripts/audit-memory-duplicates.mjs +44 -0
  1123. package/scripts/measure-claude-hook-overhead.mjs +77 -0
  1124. package/scripts/recover-user-config.mjs +254 -0
  1125. package/scripts/restore-data-home-from-backup.mjs +239 -0
  1126. package/setup.js +804 -260
  1127. package/skills/leonardo/SKILL.md +19 -10
  1128. package/skills/leonardo/modules/image-prompter.md +18 -12
  1129. package/skills/leonardo/modules/video-prompter.md +19 -13
  1130. package/skills/synabun/SKILL.md +209 -185
  1131. package/skills/synabun/icon.png +0 -0
  1132. package/skills/synabun/modules/audit.md +380 -374
  1133. package/skills/synabun/modules/changelog.md +15 -6
  1134. package/skills/synabun/modules/idea.md +148 -144
  1135. package/skills/synabun/modules/memorize.md +13 -4
  1136. package/skills/synabun/modules/schedule.md +198 -0
  1137. package/skills/synabun/synabunicon.png +0 -0
  1138. package/updater.cmd +31 -0
  1139. package/updater.mjs +382 -0
  1140. package/updater.sh +29 -0
  1141. package/hooks/claude-code/test-user-learning.mjs +0 -531
  1142. package/neural-interface/public/claude-chat.css +0 -878
  1143. package/neural-interface/public/claude-chat.html +0 -92
  1144. package/neural-interface/public/claude-chat.js +0 -1168
  1145. package/neural-interface/public/index-legacy.html +0 -14677
  1146. package/neural-interface/public/index2d-legacy.html +0 -8193
  1147. package/neural-interface/public/shared/html-term-renderer.js +0 -1022
  1148. package/neural-interface/public/variant/3d/background.js +0 -884
  1149. package/neural-interface/public/variant/3d/camera.js +0 -661
  1150. package/neural-interface/public/variant/3d/gfx.js +0 -116
  1151. package/neural-interface/public/variant/3d/graph.js +0 -2399
  1152. package/neural-interface/public/variant/3d/settings-gfx.js +0 -228
  1153. package/neural-interface/templates/CLAUDE-template.md +0 -211
@@ -1,2399 +0,0 @@
1
- // ═══════════════════════════════════════════
2
- // SynaBun Neural Interface — 3D Graph (Raw Three.js)
3
- // Core graph initialization, node/link rendering,
4
- // layout computation, animation loop, interactions
5
- // ═══════════════════════════════════════════
6
- //
7
- // THREE, TWEEN, OrbitControls, EffectComposer, RenderPass, UnrealBloomPass
8
- // are globals from CDN imports. No ForceGraph3D dependency.
9
- console.log('[graph.js] LOADED — v4 polished layout + fresnel orbs');
10
-
11
- import { state, emit, on } from '../../shared/state.js';
12
- import { KEYS } from '../../shared/constants.js';
13
- import { storage } from '../../shared/storage.js';
14
- import { catColor } from '../../shared/colors.js';
15
- import { fetchLinks } from '../../shared/api.js';
16
- import { gfx } from './gfx.js';
17
-
18
- // ── Constants ──────────────────────────────
19
- const FLOOR_Y = -500;
20
- const PLEXUS_RADIUS = 200;
21
- const _MULTI_SELECT_BLUE = new THREE.Color(0.4, 0.7, 1.0);
22
- const _MAX_BATCH_LINKS = 15000;
23
- const _posStorageKey = KEYS.NODE_POS_3D;
24
-
25
- // ── Module state ───────────────────────────
26
- let graph = null;
27
- let _graphContainer = null;
28
- let animFrameId = null;
29
- let graphRemovalTimer = null;
30
- let _bloomPass = null;
31
-
32
- // Frustum culling (reused every frame — zero alloc)
33
- const _worldPos = new THREE.Vector3();
34
- const _mouseDir = new THREE.Vector3();
35
- const _frustum = new THREE.Frustum();
36
- const _frustumPadded = new THREE.Frustum();
37
- const _projScreenMatrix = new THREE.Matrix4();
38
-
39
- // Batch link rendering — single draw call for ALL visible links
40
- let _linkBatch = null;
41
- let _linkBatchGeo = null;
42
- let _linkBatchDirty = true;
43
- let _linkPosDirty = true; // positions need update (drag, layout change)
44
- let _batchLinks = [];
45
- let _visualLinks = [];
46
- let _nodeById = new Map();
47
- let _linkBatchPositions = new Float32Array(_MAX_BATCH_LINKS * 6);
48
- let _linkBatchColors = new Float32Array(_MAX_BATCH_LINKS * 6);
49
- let _crossCategoryLinks = [];
50
-
51
- // Drag state
52
- const _drag = {
53
- active: false,
54
- node: null,
55
- type: null,
56
- dragSet: new Set(),
57
- frozenSet: new Set(),
58
- prevPos: null,
59
- depthOffset: new THREE.Vector3(),
60
- };
61
-
62
- // 3D mouse position tracking via raycasting
63
- const _mouse = new THREE.Vector2();
64
- const _raycaster = new THREE.Raycaster();
65
- const _mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
66
- const _mouse3D = new THREE.Vector3();
67
- let _mouse3DValid = false;
68
- let _mouseMoved = false;
69
- const _dragDepthVec = new THREE.Vector3();
70
-
71
- // Node scale boost when links are off
72
- let noLinksScaleBoost = 1.0;
73
-
74
- // Pointer-over-UI guard
75
- let _pointerOverUI = false;
76
-
77
- // Focus mode — true when visualization is paused (zero-resource mode)
78
- let _focusPaused = false;
79
-
80
- // ── Raw Three.js objects (replaces ForceGraph3D) ──
81
- let _scene = null;
82
- let _camera = null;
83
- let _renderer = null;
84
- let _controls = null;
85
- let _composer = null;
86
-
87
- // ── Graph data store (replaces ForceGraph3D's internal data) ──
88
- let _graphNodes = [];
89
- let _graphLinks = [];
90
-
91
- // ── Anchor/Tag scene objects (memory nodes have ZERO Three.js objects) ──
92
- const _anchorTagObjects = new Map(); // nodeId → THREE.Group
93
- let _anchorTagArray = []; // flat array for fast iteration in animate()
94
-
95
- // ── Pointer events state for custom raycasting ──
96
- let _pointerDownPos = null;
97
- let _pointerDownTime = 0;
98
- let _pointerDownNode = null;
99
- const _dragPlane = new THREE.Plane();
100
- const _dragHit = new THREE.Vector3();
101
-
102
- // ═══════════════════════════════════════════
103
- // GRAPH PROXY — matches ForceGraph3D API surface
104
- // so camera.js, background.js, main.js need zero changes
105
- // ═══════════════════════════════════════════
106
-
107
- function _tweenCameraPosition(toPos, toLookAt, durationMs) {
108
- if (!_camera || !_controls) return;
109
- if (!durationMs || durationMs <= 0) {
110
- _camera.position.set(toPos.x, toPos.y, toPos.z);
111
- if (toLookAt) {
112
- _controls.target.set(toLookAt.x, toLookAt.y, toLookAt.z);
113
- _controls.update();
114
- }
115
- return;
116
- }
117
- new TWEEN.Tween(_camera.position)
118
- .to({ x: toPos.x, y: toPos.y, z: toPos.z }, durationMs)
119
- .easing(TWEEN.Easing.Quadratic.Out)
120
- .start();
121
- if (toLookAt) {
122
- new TWEEN.Tween(_controls.target)
123
- .to({ x: toLookAt.x, y: toLookAt.y, z: toLookAt.z }, durationMs)
124
- .easing(TWEEN.Easing.Quadratic.Out)
125
- .onUpdate(() => _controls.update())
126
- .start();
127
- }
128
- }
129
-
130
- const graphProxy = {
131
- scene: () => _scene,
132
- camera: () => _camera,
133
- controls: () => _controls,
134
- renderer: () => _renderer,
135
- graphData: (data) => {
136
- if (data !== undefined) {
137
- _graphNodes = data.nodes || [];
138
- _graphLinks = data.links || [];
139
- } else {
140
- return { nodes: _graphNodes, links: _graphLinks };
141
- }
142
- },
143
- cameraPosition: (pos, lookAt, ms) => _tweenCameraPosition(pos, lookAt, ms ?? 0),
144
- postProcessingComposer: () => _composer,
145
- backgroundColor: (hex) => {
146
- if (_renderer) _renderer.setClearColor(new THREE.Color(hex));
147
- },
148
- d3Force: () => ({ strength: () => ({}) }), // noop — forces are disabled
149
- };
150
-
151
- // ═══════════════════════════════════════════
152
- // INSTANCED RENDERING — memory nodes
153
- // ═══════════════════════════════════════════
154
- const _MAX_MEMORY_NODES = 8000;
155
- const _NODE_LIMIT_KEY = 'neural-node-limit';
156
- let _nodeLimit = parseInt(storage.getItem(_NODE_LIMIT_KEY) || '0', 10) || 0; // 0 = no limit
157
-
158
- // 3 InstancedMesh for wireframes (one per LOD tier)
159
- let _wireInstLow = null; // importance 1-4
160
- let _wireInstMed = null; // importance 5-7
161
- let _wireInstHigh = null; // importance 8+
162
-
163
- // 1 Points mesh for glows
164
- let _glowPoints = null;
165
- let _glowPointsGeo = null;
166
-
167
- // Index management
168
- let _nodeInstanceMap = new Map(); // nodeId → { tier, index }
169
- let _tierNodes = [[], [], []]; // [lowNodes, medNodes, highNodes]
170
- let _glowNodeOrder = []; // all memory nodes in global index order
171
-
172
- // Per-node state (parallel Float32Arrays — static, updated only on dirty)
173
- const _nodeOpacity = new Float32Array(_MAX_MEMORY_NODES);
174
- const _nodeGlowOpacity = new Float32Array(_MAX_MEMORY_NODES);
175
- const _nodeScale = new Float32Array(_MAX_MEMORY_NODES);
176
- const _nodeColorR = new Float32Array(_MAX_MEMORY_NODES);
177
- const _nodeColorG = new Float32Array(_MAX_MEMORY_NODES);
178
- const _nodeColorB = new Float32Array(_MAX_MEMORY_NODES);
179
- const _nodeBaseColorR = new Float32Array(_MAX_MEMORY_NODES);
180
- const _nodeBaseColorG = new Float32Array(_MAX_MEMORY_NODES);
181
- const _nodeBaseColorB = new Float32Array(_MAX_MEMORY_NODES);
182
- const _nodeBaseOpacity = new Float32Array(_MAX_MEMORY_NODES);
183
- const _nodeImportance = new Float32Array(_MAX_MEMORY_NODES);
184
- const _nodeBaseRadius = new Float32Array(_MAX_MEMORY_NODES);
185
-
186
- // Dirty flag — only recompute + upload GPU buffers when state changes
187
- let _instancesDirty = true;
188
-
189
- // Reusable math scratch objects (zero-alloc per frame)
190
- const _instMatrix = new THREE.Matrix4();
191
- const _instPos = new THREE.Vector3();
192
- const _instScaleV = new THREE.Vector3();
193
- const _identityQuat = new THREE.Quaternion(); // identity — no rotation
194
-
195
- // ═══════════════════════════════════════════
196
- // SOFT DOT TEXTURE
197
- // ═══════════════════════════════════════════
198
- let _softDotTex = null;
199
- function getSoftDotTexture() {
200
- if (_softDotTex) return _softDotTex;
201
- const size = 64;
202
- const canvas = document.createElement('canvas');
203
- canvas.width = size; canvas.height = size;
204
- const ctx = canvas.getContext('2d');
205
- const c = size / 2;
206
- const imgData = ctx.createImageData(size, size);
207
- const d = imgData.data;
208
- for (let py = 0; py < size; py++) {
209
- for (let px = 0; px < size; px++) {
210
- const dx = (px - c) / c, dy = (py - c) / c;
211
- const dist = Math.sqrt(dx * dx + dy * dy);
212
- const t = Math.max(0, Math.min(1, (0.55 - dist) / (0.55 - 0.1)));
213
- const alpha = t * t * (3 - 2 * t);
214
- const idx = (py * size + px) * 4;
215
- d[idx] = 255; d[idx + 1] = 255; d[idx + 2] = 255;
216
- d[idx + 3] = alpha * 255 | 0;
217
- }
218
- }
219
- ctx.putImageData(imgData, 0, 0);
220
- _softDotTex = new THREE.CanvasTexture(canvas);
221
- _softDotTex.needsUpdate = true;
222
- return _softDotTex;
223
- }
224
-
225
- // ── Shared hitbox material for anchor/tag PlaneGeometry hitboxes (~50-100 total) ──
226
- let _sharedHitboxMat = null;
227
- function getHitboxMaterial() {
228
- if (!_sharedHitboxMat) {
229
- _sharedHitboxMat = new THREE.MeshBasicMaterial({
230
- transparent: true, opacity: 0, depthWrite: false, side: THREE.DoubleSide,
231
- });
232
- }
233
- return _sharedHitboxMat;
234
- }
235
-
236
- // ═══════════════════════════════════════════
237
- // INSTANCED SHADER MATERIALS
238
- // ═══════════════════════════════════════════
239
-
240
- function createWireInstanceMaterial() {
241
- return new THREE.ShaderMaterial({
242
- wireframe: false,
243
- transparent: true,
244
- depthWrite: true,
245
- side: THREE.DoubleSide,
246
- uniforms: {
247
- uTime: { value: 0.0 },
248
- },
249
- vertexShader: `
250
- attribute vec3 instanceColor;
251
- attribute float instanceOpacity;
252
- varying vec3 vColor;
253
- varying float vOpacity;
254
- varying vec3 vNormal;
255
- varying vec3 vViewPos;
256
- void main() {
257
- vColor = instanceColor;
258
- vOpacity = instanceOpacity;
259
- vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4(position, 1.0);
260
- vNormal = normalize(normalMatrix * mat3(instanceMatrix) * normal);
261
- vViewPos = mvPosition.xyz;
262
- gl_Position = projectionMatrix * mvPosition;
263
- }
264
- `,
265
- fragmentShader: `
266
- uniform float uTime;
267
- varying vec3 vColor;
268
- varying float vOpacity;
269
- varying vec3 vNormal;
270
- varying vec3 vViewPos;
271
- void main() {
272
- if (vOpacity < 0.003) discard;
273
- // Fresnel rim glow — brighter at edges, subtler at center
274
- float fresnel = 1.0 - abs(dot(normalize(vNormal), normalize(-vViewPos)));
275
- fresnel = pow(fresnel, 1.5);
276
- float rim = 0.7 + fresnel * 0.3;
277
- // Subtle shimmer
278
- float shimmer = 1.0 + sin(uTime * 1.5 + vViewPos.x * 0.1) * 0.05;
279
- gl_FragColor = vec4(vColor * 1.8 * rim * shimmer, 1.0);
280
- }
281
- `,
282
- });
283
- }
284
-
285
- function createGlowPointsMaterial() {
286
- return new THREE.ShaderMaterial({
287
- transparent: true,
288
- depthWrite: false,
289
- uniforms: {
290
- uTexture: { value: getSoftDotTexture() },
291
- },
292
- vertexShader: `
293
- attribute vec3 glowColor;
294
- attribute float glowOpacity;
295
- attribute float glowSize;
296
- varying vec3 vColor;
297
- varying float vOpacity;
298
- void main() {
299
- vColor = glowColor;
300
- vOpacity = glowOpacity;
301
- vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
302
- gl_PointSize = glowSize * (300.0 / -mvPosition.z);
303
- gl_PointSize = clamp(gl_PointSize, 1.0, 128.0);
304
- gl_Position = projectionMatrix * mvPosition;
305
- }
306
- `,
307
- fragmentShader: `
308
- uniform sampler2D uTexture;
309
- varying vec3 vColor;
310
- varying float vOpacity;
311
- void main() {
312
- if (vOpacity < 0.003) discard;
313
- vec4 texel = texture2D(uTexture, gl_PointCoord);
314
- gl_FragColor = vec4(vColor * 1.8, texel.a * vOpacity * 2.0);
315
- }
316
- `,
317
- });
318
- }
319
-
320
- // ═══════════════════════════════════════════
321
- // CATEGORY LOGOS — preloaded images for anchor nodes
322
- // ═══════════════════════════════════════════
323
- const _categoryLogos = new Map();
324
-
325
- let _logoRefreshTimer = null;
326
- export function preloadCategoryLogos(categories) {
327
- const names = new Set(categories.map(c => c.name));
328
- for (const [k] of _categoryLogos) { if (!names.has(k)) _categoryLogos.delete(k); }
329
- for (const cat of categories) {
330
- if (!cat.logo) continue;
331
- const existing = _categoryLogos.get(cat.name);
332
- if (existing && existing.src === cat.logo) continue;
333
- const img = new Image();
334
- img.crossOrigin = 'anonymous';
335
- const catName = cat.name;
336
- const entry = { img, ready: false, src: cat.logo };
337
- img.onload = () => {
338
- entry.ready = true;
339
- // Remove existing anchor so applyGraphData recreates it with the logo
340
- for (const [id, obj] of _anchorTagObjects) {
341
- if (obj.userData.anchorCategory === catName) {
342
- _scene.remove(obj);
343
- _anchorTagObjects.delete(id);
344
- break;
345
- }
346
- }
347
- // Debounced graph refresh so logos appear on anchors once loaded
348
- clearTimeout(_logoRefreshTimer);
349
- _logoRefreshTimer = setTimeout(() => { if (graph) applyGraphData(); }, 200);
350
- };
351
- img.onerror = () => { _categoryLogos.delete(cat.name); };
352
- img.src = cat.logo;
353
- _categoryLogos.set(cat.name, entry);
354
- }
355
- }
356
-
357
- // Legacy fallback: hardcoded OpenClaw logo
358
- const _openclawLogo = new Image();
359
- _openclawLogo.src = '/openclaw-logo-text.png';
360
- let _openclawLogoReady = false;
361
- _openclawLogo.onload = () => { _openclawLogoReady = true; };
362
-
363
- // ═══════════════════════════════════════════
364
- // INSTANCED RENDERING — init + index management
365
- // ═══════════════════════════════════════════
366
-
367
- function initInstancedRendering() {
368
- const scene = graph.scene();
369
-
370
- // 3 InstancedMesh for wireframes (one per LOD tier)
371
- const geoLow = new THREE.IcosahedronGeometry(1, 0);
372
- const geoMed = new THREE.IcosahedronGeometry(1, 1);
373
- const geoHigh = new THREE.IcosahedronGeometry(1, 2);
374
-
375
- _wireInstLow = new THREE.InstancedMesh(geoLow, createWireInstanceMaterial(), _MAX_MEMORY_NODES);
376
- _wireInstMed = new THREE.InstancedMesh(geoMed, createWireInstanceMaterial(), _MAX_MEMORY_NODES);
377
- _wireInstHigh = new THREE.InstancedMesh(geoHigh, createWireInstanceMaterial(), _MAX_MEMORY_NODES);
378
-
379
- for (const inst of [_wireInstLow, _wireInstMed, _wireInstHigh]) {
380
- inst.count = 0;
381
- inst.frustumCulled = false;
382
-
383
- const colorAttr = new THREE.InstancedBufferAttribute(
384
- new Float32Array(_MAX_MEMORY_NODES * 3), 3
385
- );
386
- colorAttr.setUsage(THREE.DynamicDrawUsage);
387
- inst.geometry.setAttribute('instanceColor', colorAttr);
388
-
389
- const opacityAttr = new THREE.InstancedBufferAttribute(
390
- new Float32Array(_MAX_MEMORY_NODES), 1
391
- );
392
- opacityAttr.setUsage(THREE.DynamicDrawUsage);
393
- inst.geometry.setAttribute('instanceOpacity', opacityAttr);
394
-
395
- scene.add(inst);
396
- }
397
-
398
- // 1 Points mesh for glows
399
- _glowPointsGeo = new THREE.BufferGeometry();
400
-
401
- const posAttr = new THREE.BufferAttribute(new Float32Array(_MAX_MEMORY_NODES * 3), 3);
402
- posAttr.setUsage(THREE.DynamicDrawUsage);
403
- _glowPointsGeo.setAttribute('position', posAttr);
404
-
405
- const glowColorAttr = new THREE.BufferAttribute(new Float32Array(_MAX_MEMORY_NODES * 3), 3);
406
- glowColorAttr.setUsage(THREE.DynamicDrawUsage);
407
- _glowPointsGeo.setAttribute('glowColor', glowColorAttr);
408
-
409
- const glowOpAttr = new THREE.BufferAttribute(new Float32Array(_MAX_MEMORY_NODES), 1);
410
- glowOpAttr.setUsage(THREE.DynamicDrawUsage);
411
- _glowPointsGeo.setAttribute('glowOpacity', glowOpAttr);
412
-
413
- const glowSizeAttr = new THREE.BufferAttribute(new Float32Array(_MAX_MEMORY_NODES), 1);
414
- glowSizeAttr.setUsage(THREE.DynamicDrawUsage);
415
- _glowPointsGeo.setAttribute('glowSize', glowSizeAttr);
416
-
417
- _glowPointsGeo.setDrawRange(0, 0);
418
-
419
- _glowPoints = new THREE.Points(_glowPointsGeo, createGlowPointsMaterial());
420
- _glowPoints.frustumCulled = false;
421
- scene.add(_glowPoints);
422
- }
423
-
424
- function rebuildInstanceMap() {
425
- _nodeInstanceMap.clear();
426
- _tierNodes[0].length = 0;
427
- _tierNodes[1].length = 0;
428
- _tierNodes[2].length = 0;
429
- _glowNodeOrder.length = 0;
430
-
431
- if (!graph) return;
432
- const gd = graph.graphData();
433
-
434
- // First pass: assign nodes to tiers (cap at effective limit to prevent buffer overflow)
435
- const effectiveLimit = _nodeLimit > 0 ? Math.min(_nodeLimit, _MAX_MEMORY_NODES) : _MAX_MEMORY_NODES;
436
- let memCount = 0;
437
- for (let i = 0; i < gd.nodes.length; i++) {
438
- const node = gd.nodes[i];
439
- if (!node.payload || node.payload._isAnchor || node.payload._isTag) continue;
440
- if (memCount >= effectiveLimit) break;
441
-
442
- const importance = node.payload.importance || 5;
443
- const tier = importance >= 8 ? 2 : importance >= 5 ? 1 : 0;
444
-
445
- _tierNodes[tier].push(node);
446
- _nodeInstanceMap.set(node.id, { tier, index: _tierNodes[tier].length - 1 });
447
- memCount++;
448
- }
449
-
450
- // Build _glowNodeOrder in tier order (tier 0, then tier 1, then tier 2)
451
- // so global indices match Phase 2's globalOffset mapping
452
- for (let t = 0; t < 3; t++) {
453
- for (let i = 0; i < _tierNodes[t].length; i++) {
454
- _glowNodeOrder.push(_tierNodes[t][i]);
455
- }
456
- }
457
-
458
- // Initialize animation state for each node (now in tier order)
459
- for (let gi = 0; gi < _glowNodeOrder.length; gi++) {
460
- const node = _glowNodeOrder[gi];
461
- const importance = node.payload.importance || 5;
462
- const color = catColor(node.payload.category);
463
- const hex = new THREE.Color(color);
464
- const mutedHex = hex.clone();
465
- const radius = 6 + (importance - 1) * 0.8;
466
- const baseOpacity = 0.75 + (importance - 1) * 0.03;
467
-
468
- _nodeBaseOpacity[gi] = baseOpacity;
469
- _nodeBaseColorR[gi] = mutedHex.r;
470
- _nodeBaseColorG[gi] = mutedHex.g;
471
- _nodeBaseColorB[gi] = mutedHex.b;
472
- _nodeColorR[gi] = mutedHex.r;
473
- _nodeColorG[gi] = mutedHex.g;
474
- _nodeColorB[gi] = mutedHex.b;
475
- _nodeOpacity[gi] = baseOpacity;
476
- _nodeGlowOpacity[gi] = baseOpacity * 0.85;
477
- _nodeScale[gi] = 1.0;
478
- _nodeImportance[gi] = importance;
479
- _nodeBaseRadius[gi] = radius;
480
- }
481
-
482
- _instancesDirty = true;
483
-
484
- // Set instance counts
485
- if (_wireInstLow) _wireInstLow.count = _tierNodes[0].length;
486
- if (_wireInstMed) _wireInstMed.count = _tierNodes[1].length;
487
- if (_wireInstHigh) _wireInstHigh.count = _tierNodes[2].length;
488
-
489
- // Set glow draw range
490
- if (_glowPointsGeo) _glowPointsGeo.setDrawRange(0, _glowNodeOrder.length);
491
- }
492
-
493
- // GFX preset resets — handle instanced memory nodes + individual anchor/tag nodes
494
- on('gfx:preset-applied', () => {
495
- // Reset instanced memory node opacities to base values
496
- for (let gi = 0; gi < _glowNodeOrder.length; gi++) {
497
- _nodeOpacity[gi] = _nodeBaseOpacity[gi];
498
- _nodeGlowOpacity[gi] = _nodeBaseOpacity[gi] * 0.85;
499
- }
500
- _instancesDirty = true;
501
- // Reset individual anchor/tag nodes
502
- for (const [, obj] of _anchorTagObjects) {
503
- if (!obj || !obj.userData) continue;
504
- const dot = obj.userData.dot;
505
- if (dot && dot.material) {
506
- dot.material.opacity = obj.userData.baseOpacity || 0.1;
507
- }
508
- }
509
- });
510
-
511
- // Node limit change — save to storage and rebuild
512
- on('search:apply', () => { _instancesDirty = true; });
513
- on('search:clear', () => { _instancesDirty = true; });
514
- on('categories-changed', () => { _instancesDirty = true; });
515
-
516
- on('node-limit-changed', (limit) => {
517
- _nodeLimit = limit;
518
- storage.setItem(_NODE_LIMIT_KEY, String(limit));
519
- if (graph) {
520
- rebuildInstanceMap();
521
- _instancesDirty = true;
522
- emit('graph:refresh');
523
- }
524
- });
525
-
526
-
527
- // ═══════════════════════════════════════════
528
- // NODE CREATION — Anchor (parent category)
529
- // ═══════════════════════════════════════════
530
- function createAnchorObject(node) {
531
- const parentName = node.payload._anchorCategory;
532
- const color = catColor(parentName);
533
- const hex = new THREE.Color(color);
534
- const dotSize = 20;
535
-
536
- const group = new THREE.Group();
537
-
538
- // Label — logo or text on canvas
539
- const _logoEntry = _categoryLogos.get(parentName);
540
- const useLogo = (_logoEntry && _logoEntry.ready) || (parentName === 'openclaw' && _openclawLogoReady);
541
- const logoImage = (_logoEntry && _logoEntry.ready) ? _logoEntry.img : _openclawLogo;
542
- if (_logoEntry) console.log(`[anchor] ${parentName}: logo entry found, ready=${_logoEntry.ready}, src=${_logoEntry.src}`);
543
- else console.log(`[anchor] ${parentName}: no logo entry in _categoryLogos (map size: ${_categoryLogos.size})`);
544
-
545
- let contentW, contentH;
546
- const PAD = 16;
547
-
548
- if (useLogo) {
549
- const aspect = logoImage.naturalWidth / (logoImage.naturalHeight || 1);
550
- const maxW = 380, maxH = 100;
551
- if (aspect >= maxW / maxH) { contentW = maxW; contentH = maxW / aspect; }
552
- else { contentH = maxH; contentW = maxH * aspect; }
553
- } else {
554
- const measureCanvas = document.createElement('canvas');
555
- const measureCtx = measureCanvas.getContext('2d');
556
- measureCtx.font = '600 48px "Space Grotesk", "Inter", system-ui, sans-serif';
557
- const metrics = measureCtx.measureText(parentName.toUpperCase());
558
- contentW = Math.ceil(metrics.width);
559
- contentH = 58;
560
- }
561
-
562
- const canvasW = Math.ceil(contentW + PAD * 2);
563
- const canvasH = Math.ceil(contentH + PAD * 2);
564
-
565
- const labelCanvas = document.createElement('canvas');
566
- const labelCtx = labelCanvas.getContext('2d');
567
- labelCanvas.width = canvasW;
568
- labelCanvas.height = canvasH;
569
- labelCtx.clearRect(0, 0, canvasW, canvasH);
570
-
571
- if (useLogo) {
572
- labelCtx.globalAlpha = 1.0;
573
- labelCtx.drawImage(logoImage, PAD, PAD, contentW, contentH);
574
- labelCtx.globalAlpha = 1.0;
575
- } else {
576
- labelCtx.font = '600 48px "Space Grotesk", "Inter", system-ui, sans-serif';
577
- labelCtx.textAlign = 'center';
578
- labelCtx.textBaseline = 'middle';
579
- labelCtx.fillStyle = 'rgba(255,255,255,1.0)';
580
- labelCtx.fillText(parentName.toUpperCase(), canvasW / 2, canvasH / 2);
581
- }
582
-
583
- const labelTex = new THREE.CanvasTexture(labelCanvas);
584
- labelTex.colorSpace = THREE.SRGBColorSpace;
585
-
586
- // Billboard mesh with custom ShaderMaterial — bypasses SpriteMaterial pipeline entirely
587
- const SCALE = 0.3;
588
- const labelW = canvasW * SCALE;
589
- const labelH = canvasH * SCALE;
590
- const labelGeo = new THREE.PlaneGeometry(1, 1); // 1x1 base — scale set in animate loop via baseLabelScale
591
- const labelShaderMat = new THREE.ShaderMaterial({
592
- transparent: true,
593
- depthTest: false,
594
- depthWrite: false,
595
- fog: false,
596
- uniforms: {
597
- uTexture: { value: labelTex },
598
- uOpacity: { value: 1.0 },
599
- },
600
- vertexShader: `
601
- varying vec2 vUv;
602
- void main() {
603
- vUv = uv;
604
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
605
- }
606
- `,
607
- fragmentShader: `
608
- uniform sampler2D uTexture;
609
- uniform float uOpacity;
610
- varying vec2 vUv;
611
- void main() {
612
- vec4 tex = texture2D(uTexture, vUv);
613
- if (tex.a < 0.01) discard;
614
- gl_FragColor = vec4(tex.rgb, tex.a * uOpacity);
615
- }
616
- `,
617
- });
618
- const label = new THREE.Mesh(labelGeo, labelShaderMat);
619
- label.renderOrder = 999;
620
- label.position.set(0, 0, 0.5);
621
- group.add(label);
622
-
623
- // Flat plane hitbox (shared material)
624
- const hitGeo = new THREE.PlaneGeometry(labelW, labelH);
625
- const hitbox = new THREE.Mesh(hitGeo, getHitboxMaterial());
626
- hitbox.position.set(0, 0, 0.5);
627
- group.add(hitbox);
628
-
629
- group.userData.nodeId = node.id;
630
- group.userData.isAnchor = true;
631
- group.userData.anchorCategory = parentName;
632
- group.userData.dot = null;
633
- group.userData.label = label;
634
- group.userData.baseLabelScale = { x: labelW, y: labelH };
635
- group.userData.baseLabelY = 0;
636
- group.userData.baseRadius = dotSize;
637
- group.userData.category = parentName;
638
- group.userData.phase = parentName.length * 0.7;
639
- group.userData.importance = 10;
640
- group.userData.baseOpacity = 1.0;
641
-
642
- group.userData._currentScale = 0.01;
643
- group.scale.setScalar(0.01);
644
-
645
- return group;
646
- }
647
-
648
- // ═══════════════════════════════════════════
649
- // NODE CREATION — Tag (child category)
650
- // ═══════════════════════════════════════════
651
- function createTagObject(node) {
652
- const catName = node.payload._tagCategory;
653
- const color = catColor(catName);
654
- const hex = new THREE.Color(color);
655
- const dotSize = 10;
656
-
657
- const group = new THREE.Group();
658
-
659
- // Visible dot sprite
660
- const dotMat = new THREE.SpriteMaterial({
661
- map: getSoftDotTexture(),
662
- color: hex,
663
- transparent: true,
664
- opacity: 1.0,
665
- blending: THREE.NormalBlending,
666
- depthWrite: false,
667
- fog: false,
668
- });
669
- const dot = new THREE.Sprite(dotMat);
670
- dot.scale.set(dotSize, dotSize, 1);
671
- dot.raycast = () => {};
672
- group.add(dot);
673
-
674
- // Small text label
675
- const measureCanvas = document.createElement('canvas');
676
- const measureCtx = measureCanvas.getContext('2d');
677
- measureCtx.font = '500 38px "JetBrains Mono", "Space Grotesk", monospace';
678
- const tagMetrics = measureCtx.measureText(catName);
679
- const tagTextW = Math.ceil(tagMetrics.width);
680
- const tagTextH = 48;
681
- const tagPad = 12;
682
- const tagCanvasW = tagTextW + tagPad * 2;
683
- const tagCanvasH = tagTextH + tagPad * 2;
684
-
685
- const labelCanvas = document.createElement('canvas');
686
- const labelCtx = labelCanvas.getContext('2d');
687
- labelCanvas.width = tagCanvasW;
688
- labelCanvas.height = tagCanvasH;
689
- labelCtx.clearRect(0, 0, tagCanvasW, tagCanvasH);
690
- labelCtx.font = '500 38px "JetBrains Mono", "Space Grotesk", monospace';
691
- labelCtx.textAlign = 'center';
692
- labelCtx.textBaseline = 'middle';
693
- labelCtx.fillStyle = color;
694
- labelCtx.fillText(catName, tagCanvasW / 2, tagCanvasH / 2);
695
-
696
- const labelTex = new THREE.CanvasTexture(labelCanvas);
697
- labelTex.colorSpace = THREE.SRGBColorSpace;
698
-
699
- // Billboard mesh with custom ShaderMaterial — bypasses SpriteMaterial pipeline
700
- const TAG_SCALE = 0.25;
701
- const tagLabelW = tagCanvasW * TAG_SCALE;
702
- const tagLabelH = tagCanvasH * TAG_SCALE;
703
- const tagLabelGeo = new THREE.PlaneGeometry(1, 1); // 1x1 base — scale set in animate loop via baseLabelScale
704
- const tagLabelShaderMat = new THREE.ShaderMaterial({
705
- transparent: true,
706
- depthTest: false,
707
- depthWrite: false,
708
- fog: false,
709
- uniforms: {
710
- uTexture: { value: labelTex },
711
- uOpacity: { value: 1.0 },
712
- },
713
- vertexShader: `
714
- varying vec2 vUv;
715
- void main() {
716
- vUv = uv;
717
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
718
- }
719
- `,
720
- fragmentShader: `
721
- uniform sampler2D uTexture;
722
- uniform float uOpacity;
723
- varying vec2 vUv;
724
- void main() {
725
- vec4 tex = texture2D(uTexture, vUv);
726
- if (tex.a < 0.01) discard;
727
- gl_FragColor = vec4(tex.rgb, tex.a * uOpacity);
728
- }
729
- `,
730
- });
731
- const label = new THREE.Mesh(tagLabelGeo, tagLabelShaderMat);
732
- label.renderOrder = 999;
733
- label.position.set(0, dotSize * 0.8, 0);
734
- group.add(label);
735
-
736
- // Flat plane hitbox (shared material)
737
- const hitW = Math.max(tagLabelW, dotSize);
738
- const hitH = tagLabelH + dotSize;
739
- const hitGeo = new THREE.PlaneGeometry(hitW, hitH);
740
- const hitbox = new THREE.Mesh(hitGeo, getHitboxMaterial());
741
- hitbox.position.set(0, dotSize * 0.4, 0);
742
- group.add(hitbox);
743
-
744
- group.userData.nodeId = node.id;
745
- group.userData.isTag = true;
746
- group.userData.tagCategory = catName;
747
- group.userData.dot = dot;
748
- group.userData.label = label;
749
- group.userData.baseLabelScale = { x: tagLabelW, y: tagLabelH };
750
- group.userData.baseLabelY = dotSize * 0.8;
751
- group.userData.baseRadius = dotSize;
752
- group.userData.category = catName;
753
- group.userData.phase = catName.split('').reduce((a, c) => a + c.charCodeAt(0), 0) * 0.3;
754
- group.userData.importance = 8;
755
- group.userData.baseOpacity = 1.0;
756
-
757
- group.userData._currentScale = 0.01;
758
- group.scale.setScalar(0.01);
759
-
760
- return group;
761
- }
762
-
763
- // ═══════════════════════════════════════════
764
- // MOUSE 3D POSITION — raycasting for plexus
765
- // ═══════════════════════════════════════════
766
-
767
- function _initMouseTracking() {
768
- document.addEventListener('mousemove', (e) => {
769
- if (_focusPaused) return;
770
- // Use container bounds for correct raycasting when explorer sidebar shifts the graph
771
- const rect = _graphContainer
772
- ? _graphContainer.getBoundingClientRect()
773
- : { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
774
- _mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
775
- _mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
776
- _mouse3DValid = true;
777
- _mouseMoved = true;
778
- });
779
-
780
- // Wheel-during-drag: move node along camera→node line of sight.
781
- // Uses capture phase on the container so we intercept BEFORE OrbitControls.
782
- // Also directly moves the Three.js mesh for immediate visual feedback
783
- // (onNodeDrag only fires on mousemove, not on wheel scroll).
784
- const wheelTarget = _graphContainer || document;
785
- wheelTarget.addEventListener('wheel', (e) => {
786
- if (_focusPaused) return;
787
- if (!_drag.active || !_drag.node || !graph) return;
788
-
789
- e.preventDefault();
790
- e.stopImmediatePropagation();
791
-
792
- const cam = graph.camera();
793
- const node = _drag.node;
794
-
795
- // Direction from camera to node
796
- _dragDepthVec.set(node.x || 0, node.y || 0, node.z || 0)
797
- .sub(cam.position).normalize();
798
-
799
- // 5% of distance per scroll tick, floor of 5 units
800
- const camDist = cam.position.distanceTo(node);
801
- const step = Math.max(5, camDist * 0.05);
802
- const delta = (e.deltaY < 0 ? 1 : -1) * step;
803
-
804
- // Don't let node pass behind the camera (stop ~30 units in front)
805
- const MIN_CAM_DIST = 30;
806
- if (delta < 0 && camDist <= MIN_CAM_DIST) return;
807
- const clampedDelta = delta < 0 ? Math.max(delta, -(camDist - MIN_CAM_DIST)) : delta;
808
-
809
- // Compute the offset for this tick
810
- const ox = _dragDepthVec.x * clampedDelta;
811
- const oy = _dragDepthVec.y * clampedDelta;
812
- const oz = _dragDepthVec.z * clampedDelta;
813
-
814
- // Accumulate for drag (adds depth offset on next drag move)
815
- _drag.depthOffset.x += ox;
816
- _drag.depthOffset.y += oy;
817
- _drag.depthOffset.z += oz;
818
-
819
- // Directly move node data + Three.js mesh for immediate visual feedback
820
- const gd = graph.graphData();
821
-
822
- node.x = (node.x || 0) + ox;
823
- node.y = (node.y || 0) + oy;
824
- node.z = (node.z || 0) + oz;
825
- node.fx = node.x; node.fy = node.y; node.fz = node.z;
826
- const nodeObj = _anchorTagObjects.get(node.id);
827
- if (nodeObj) nodeObj.position.set(node.x, node.y, node.z);
828
-
829
- // Move rigid-body group
830
- for (const n of gd.nodes) {
831
- if (n === node) continue;
832
- if (_drag.dragSet.has(n.id)) {
833
- n.x = (n.x || 0) + ox;
834
- n.y = (n.y || 0) + oy;
835
- n.z = (n.z || 0) + oz;
836
- n.fx = n.x; n.fy = n.y; n.fz = n.z;
837
- const nObj = _anchorTagObjects.get(n.id);
838
- if (nObj) nObj.position.set(n.x, n.y, n.z);
839
- }
840
- }
841
-
842
- // Keep prevPos in sync + mark dirty
843
- _drag.prevPos = { x: node.x, y: node.y, z: node.z };
844
- _linkPosDirty = true;
845
- _instancesDirty = true;
846
- }, { capture: true, passive: false });
847
- }
848
-
849
- function updateMouse3D() {
850
- if (!graph || !_mouse3DValid) return;
851
- const cam = graph.camera();
852
- _raycaster.setFromCamera(_mouse, cam);
853
- const controls = graph.controls();
854
- const target = controls && controls.target ? controls.target : _mouseDir.set(0, 0, 0);
855
- _mousePlane.setFromNormalAndCoplanarPoint(
856
- cam.getWorldDirection(_mouseDir).negate(),
857
- target
858
- );
859
- _raycaster.ray.intersectPlane(_mousePlane, _mouse3D);
860
- }
861
-
862
- // ═══════════════════════════════════════════
863
- // NODE POSITION PERSISTENCE
864
- // ═══════════════════════════════════════════
865
- let _posSaveTimer = null;
866
-
867
- export function saveNodePositions() {
868
- if (!graph) return;
869
- const gd = graph.graphData();
870
- const positions = {};
871
- for (const n of gd.nodes) {
872
- if (n.x != null) {
873
- positions[n.id] = { x: n.x, y: n.y, z: n.z };
874
- }
875
- }
876
- try { storage.setItem(_posStorageKey, JSON.stringify(positions)); } catch (_) {}
877
- }
878
-
879
- function restoreNodePositions(nodes) {
880
- try {
881
- const saved = JSON.parse(storage.getItem(_posStorageKey) || '{}');
882
- if (!Object.keys(saved).length) return;
883
- for (const n of nodes) {
884
- if (saved[n.id]) {
885
- const pos = saved[n.id];
886
- n.x = pos.x; n.y = pos.y; n.z = pos.z;
887
- n.fx = pos.x; n.fy = pos.y; n.fz = pos.z;
888
- }
889
- }
890
- } catch (_) {}
891
- }
892
-
893
- function schedulePositionSave() {
894
- if (_posSaveTimer) clearTimeout(_posSaveTimer);
895
- _posSaveTimer = setTimeout(saveNodePositions, 2000);
896
- }
897
-
898
- // ═══════════════════════════════════════════
899
- // BATCH LINK RENDERER — single draw call
900
- // ═══════════════════════════════════════════
901
- function initLinkBatch() {
902
- if (!graph) return;
903
- _linkBatchGeo = new THREE.BufferGeometry();
904
- _linkBatchGeo.setAttribute('position', new THREE.BufferAttribute(_linkBatchPositions, 3));
905
- _linkBatchGeo.setAttribute('color', new THREE.BufferAttribute(_linkBatchColors, 3));
906
- _linkBatchGeo.setDrawRange(0, 0);
907
- const mat = new THREE.LineBasicMaterial({
908
- vertexColors: true, transparent: true,
909
- opacity: gfx.linkOpacity || 0.12, depthWrite: false,
910
- });
911
- _linkBatch = new THREE.LineSegments(_linkBatchGeo, mat);
912
- _linkBatch.frustumCulled = false;
913
- _linkBatch.renderOrder = -1;
914
- graph.scene().add(_linkBatch);
915
- }
916
-
917
- // ═══════════════════════════════════════════
918
- // DRAG SET BUILDER — determines rigid-body group
919
- // ═══════════════════════════════════════════
920
- function _buildDragSet(node, allNodes) {
921
- const dragSet = new Set();
922
- dragSet.add(node.id);
923
-
924
- if (node.payload && node.payload._isAnchor) {
925
- const anchorCat = node.payload._anchorCategory;
926
- const childCats = Object.entries(state.categoryMetadata)
927
- .filter(([, m]) => m.parent === anchorCat)
928
- .map(([name]) => name);
929
- const treeCats = new Set([anchorCat, ...childCats]);
930
- for (const n of allNodes) {
931
- if (n === node) continue;
932
- if (n.payload._isTag && treeCats.has(n.payload._tagCategory)) dragSet.add(n.id);
933
- if (!n.payload._isAnchor && !n.payload._isTag && treeCats.has(n.payload.category)) dragSet.add(n.id);
934
- }
935
- return { type: 'anchor', dragSet };
936
- }
937
-
938
- if (node.payload && node.payload._isTag) {
939
- const tagCat = node.payload._tagCategory;
940
- for (const n of allNodes) {
941
- if (!n.payload._isAnchor && !n.payload._isTag && n.payload.category === tagCat) {
942
- dragSet.add(n.id);
943
- }
944
- }
945
- return { type: 'tag', dragSet };
946
- }
947
-
948
- // Multi-select drag
949
- if (state.multiSelected.size > 0 && state.multiSelected.has(node.id)) {
950
- for (const id of state.multiSelected) dragSet.add(id);
951
- return { type: 'multi', dragSet };
952
- }
953
-
954
- return { type: 'memory', dragSet };
955
- }
956
-
957
- // ═══════════════════════════════════════════
958
- // LAYOUT COMPUTATION — geodesic sphere packing
959
- // ═══════════════════════════════════════════
960
- function computeLayout(nodes) {
961
- const anchors = nodes.filter(n => n.payload._isAnchor);
962
- const tags = nodes.filter(n => n.payload._isTag);
963
- const memories = nodes.filter(n => !n.payload._isAnchor && !n.payload._isTag);
964
- const placed = new Set();
965
-
966
- const GOLDEN = (1 + Math.sqrt(5)) / 2;
967
-
968
- function fibSphere(n, radius, center) {
969
- const points = [];
970
- for (let i = 0; i < n; i++) {
971
- const y = 1 - (2 * i + 1) / n;
972
- const r = Math.sqrt(1 - y * y);
973
- const theta = 2 * Math.PI * i / GOLDEN;
974
- points.push({
975
- x: center.x + Math.cos(theta) * r * radius,
976
- y: center.y + y * radius,
977
- z: center.z + Math.sin(theta) * r * radius,
978
- });
979
- }
980
- return points;
981
- }
982
-
983
- // 1. Anchors in a wide ring
984
- const anchorRadius = anchors.length > 1 ? 700 + anchors.length * 200 : 0;
985
- const ANCHOR_Y = 500;
986
- const TAG_Y = ANCHOR_Y - 220;
987
- const SPHERE_GAP = 160;
988
-
989
- anchors.forEach((anchor, i) => {
990
- const angle = (i / anchors.length) * Math.PI * 2 - Math.PI / 2;
991
- anchor.x = Math.cos(angle) * anchorRadius;
992
- anchor.y = ANCHOR_Y;
993
- anchor.z = Math.sin(angle) * anchorRadius;
994
- anchor.fx = anchor.x; anchor.fy = anchor.y; anchor.fz = anchor.z;
995
- placed.add(anchor.id);
996
- });
997
-
998
- // 2. For each anchor: child tags in rings, each with memory sphere
999
- anchors.forEach(anchor => {
1000
- const cat = anchor.payload._anchorCategory;
1001
- const childTags = tags.filter(t => t.payload._parentAnchor === cat);
1002
- const directMems = memories.filter(m => m.payload.category === cat && !placed.has(m.id));
1003
-
1004
- if (childTags.length) {
1005
- const tagRingRadius = Math.max(380, childTags.length * 160);
1006
-
1007
- childTags.forEach((tag, i) => {
1008
- const angle = (i / childTags.length) * Math.PI * 2;
1009
- tag.x = anchor.x + Math.cos(angle) * tagRingRadius;
1010
- tag.y = TAG_Y;
1011
- tag.z = anchor.z + Math.sin(angle) * tagRingRadius;
1012
- tag.fx = tag.x; tag.fy = tag.y; tag.fz = tag.z;
1013
- placed.add(tag.id);
1014
-
1015
- const tagCat = tag.payload._tagCategory;
1016
- const tagMems = memories.filter(m => m.payload.category === tagCat && !placed.has(m.id));
1017
- if (tagMems.length) {
1018
- const r = 90 + Math.sqrt(tagMems.length) * 18;
1019
- const sphereCenter = { x: tag.x, y: tag.y - r - SPHERE_GAP, z: tag.z };
1020
- const positions = fibSphere(tagMems.length, r, sphereCenter);
1021
- tagMems.forEach((mem, j) => {
1022
- mem.x = positions[j].x;
1023
- mem.y = positions[j].y;
1024
- mem.z = positions[j].z;
1025
- mem.fx = mem.x; mem.fy = mem.y; mem.fz = mem.z;
1026
- placed.add(mem.id);
1027
- });
1028
- }
1029
- });
1030
- }
1031
-
1032
- // Direct-parent memories
1033
- if (directMems.length) {
1034
- const r = 90 + Math.sqrt(directMems.length) * 18;
1035
- const sphereCenter = { x: anchor.x, y: TAG_Y - r - SPHERE_GAP, z: anchor.z };
1036
- const positions = fibSphere(directMems.length, r, sphereCenter);
1037
- directMems.forEach((mem, i) => {
1038
- mem.x = positions[i].x;
1039
- mem.y = positions[i].y;
1040
- mem.z = positions[i].z;
1041
- mem.fx = mem.x; mem.fy = mem.y; mem.fz = mem.z;
1042
- placed.add(mem.id);
1043
- });
1044
- }
1045
- });
1046
-
1047
- // 3. Orphan memories
1048
- const orphans = memories.filter(m => !placed.has(m.id));
1049
- if (orphans.length) {
1050
- const catGroups = {};
1051
- orphans.forEach(m => {
1052
- const c = m.payload.category || 'uncategorized';
1053
- if (!catGroups[c]) catGroups[c] = [];
1054
- catGroups[c].push(m);
1055
- });
1056
- const groupNames = Object.keys(catGroups);
1057
- const orphanBase = anchorRadius + 400;
1058
-
1059
- groupNames.forEach((c, gi) => {
1060
- const angle = (gi / Math.max(groupNames.length, 1)) * Math.PI * 2;
1061
- const cx = Math.cos(angle) * orphanBase;
1062
- const cz = Math.sin(angle) * orphanBase;
1063
- const mems = catGroups[c];
1064
- const r = 90 + Math.sqrt(mems.length) * 18;
1065
- const positions = fibSphere(mems.length, r, { x: cx, y: 0, z: cz });
1066
-
1067
- mems.forEach((mem, i) => {
1068
- mem.x = positions[i].x;
1069
- mem.y = positions[i].y;
1070
- mem.z = positions[i].z;
1071
- mem.fx = mem.x; mem.fy = mem.y; mem.fz = mem.z;
1072
- placed.add(mem.id);
1073
- });
1074
- });
1075
- }
1076
-
1077
- // Floor clamp
1078
- const NODE_FLOOR = FLOOR_Y + 10;
1079
- for (const n of nodes) {
1080
- if (n.y < NODE_FLOOR) {
1081
- n.y = NODE_FLOOR;
1082
- if (n.fy !== undefined) n.fy = NODE_FLOOR;
1083
- }
1084
- }
1085
- }
1086
-
1087
- // ═══════════════════════════════════════════
1088
- // APPLY GRAPH DATA — inject anchors/tags, compute layout
1089
- // ═══════════════════════════════════════════
1090
- export function applyGraphData() {
1091
- if (!graph) return;
1092
-
1093
- let visibleNodes = state.allNodes.filter(n => state.activeCategories.has(n.payload.category));
1094
- let visibleIds = new Set(visibleNodes.map(n => n.id));
1095
- const nodeCatMap = {};
1096
- for (const n of visibleNodes) nodeCatMap[n.id] = n.payload.category;
1097
-
1098
- // Separate same-category links from cross-category
1099
- const sameCatLinks = [];
1100
- _crossCategoryLinks = [];
1101
- for (const l of state.allLinks) {
1102
- const srcId = l.source.id || l.source;
1103
- const tgtId = l.target.id || l.target;
1104
- if (!visibleIds.has(srcId) || !visibleIds.has(tgtId)) continue;
1105
- if (nodeCatMap[srcId] === nodeCatMap[tgtId]) {
1106
- sameCatLinks.push(l);
1107
- } else {
1108
- _crossCategoryLinks.push({ ...l, _crossCategory: true });
1109
- }
1110
- }
1111
-
1112
- _visualLinks = state.linkMode === 'all'
1113
- ? [...sameCatLinks, ..._crossCategoryLinks]
1114
- : [...sameCatLinks];
1115
- let visibleLinks = [];
1116
-
1117
- // Anchor / Tag hierarchy injection
1118
- const injectedNodes = [];
1119
- const injectedLinks = [];
1120
- const parentCats = Object.entries(state.categoryMetadata).filter(([, meta]) => meta.is_parent);
1121
-
1122
- const nodesByCat = new Map();
1123
- for (const n of visibleNodes) {
1124
- const cat = n.payload.category;
1125
- let arr = nodesByCat.get(cat);
1126
- if (!arr) { arr = []; nodesByCat.set(cat, arr); }
1127
- arr.push(n);
1128
- }
1129
-
1130
- for (const [parentName] of parentCats) {
1131
- const childCats = Object.entries(state.categoryMetadata)
1132
- .filter(([, m]) => m.parent === parentName)
1133
- .map(([name]) => name);
1134
-
1135
- const parentMems = nodesByCat.get(parentName) || [];
1136
- let hasTreeMemories = parentMems.length > 0;
1137
- if (!hasTreeMemories) {
1138
- for (const c of childCats) { if (nodesByCat.has(c)) { hasTreeMemories = true; break; } }
1139
- }
1140
- if (!hasTreeMemories) continue;
1141
-
1142
- const anchorId = `_anchor_${parentName}`;
1143
- injectedNodes.push({
1144
- id: anchorId,
1145
- payload: { category: parentName, _isAnchor: true, _anchorCategory: parentName, importance: 10, content: parentName }
1146
- });
1147
-
1148
- for (const childName of childCats) {
1149
- const childMemories = nodesByCat.get(childName) || [];
1150
- if (childMemories.length === 0) continue;
1151
-
1152
- const tagId = `_tag_${childName}`;
1153
- injectedNodes.push({
1154
- id: tagId,
1155
- payload: { category: childName, _isTag: true, _tagCategory: childName, _parentAnchor: parentName, importance: 8, content: childName }
1156
- });
1157
-
1158
- injectedLinks.push({ source: anchorId, target: tagId, strength: 0.3, _isStructural: true });
1159
-
1160
- for (const mem of childMemories) {
1161
- injectedLinks.push({ source: tagId, target: mem.id, strength: 0.5, _isStructural: true });
1162
- }
1163
- }
1164
-
1165
- for (const mem of parentMems) {
1166
- injectedLinks.push({ source: anchorId, target: mem.id, strength: 0.4, _isStructural: true });
1167
- }
1168
- }
1169
-
1170
- visibleNodes = [...injectedNodes, ...visibleNodes];
1171
- visibleIds = new Set(visibleNodes.map(n => n.id));
1172
- visibleLinks = injectedLinks;
1173
-
1174
- // Build node lookup for batch link renderer
1175
- _nodeById = new Map();
1176
- for (const n of visibleNodes) _nodeById.set(n.id, n);
1177
-
1178
- // Focus mode
1179
- if (state.focusedNodeId && visibleIds.has(state.focusedNodeId)) {
1180
- const neighborIds = new Set([state.focusedNodeId]);
1181
- const allLinksForFocus = [...visibleLinks, ..._visualLinks];
1182
- allLinksForFocus.forEach(l => {
1183
- const srcId = l.source.id || l.source;
1184
- const tgtId = l.target.id || l.target;
1185
- if (srcId === state.focusedNodeId) neighborIds.add(tgtId);
1186
- if (tgtId === state.focusedNodeId) neighborIds.add(srcId);
1187
- });
1188
- visibleNodes = visibleNodes.filter(n => neighborIds.has(n.id));
1189
- visibleIds = neighborIds;
1190
- visibleLinks = visibleLinks.filter(l => {
1191
- const srcId = l.source.id || l.source;
1192
- const tgtId = l.target.id || l.target;
1193
- return neighborIds.has(srcId) && neighborIds.has(tgtId);
1194
- });
1195
- _visualLinks = _visualLinks.filter(l => {
1196
- const srcId = l.source.id || l.source;
1197
- const tgtId = l.target.id || l.target;
1198
- return neighborIds.has(srcId) && neighborIds.has(tgtId);
1199
- });
1200
- _nodeById = new Map();
1201
- for (const n of visibleNodes) _nodeById.set(n.id, n);
1202
- }
1203
-
1204
- // Restore saved positions or compute layout
1205
- const savedPositions = JSON.parse(storage.getItem(_posStorageKey) || '{}');
1206
- const hasSaved = Object.keys(savedPositions).length > 0;
1207
-
1208
- if (hasSaved) {
1209
- restoreNodePositions(visibleNodes);
1210
- } else {
1211
- computeLayout(visibleNodes);
1212
- }
1213
-
1214
- graph.graphData({ nodes: visibleNodes, links: visibleLinks });
1215
-
1216
- // ── Sync anchor/tag Three.js objects with scene ──
1217
- const currentIds = new Set(visibleNodes.map(n => n.id));
1218
-
1219
- // Remove objects for nodes no longer present
1220
- for (const [id, obj] of _anchorTagObjects) {
1221
- if (!currentIds.has(id)) {
1222
- _scene.remove(obj);
1223
- // Dispose textures from sprites
1224
- obj.traverse(child => {
1225
- if (child.material) {
1226
- if (child.material.map) child.material.map.dispose();
1227
- child.material.dispose();
1228
- }
1229
- if (child.geometry) child.geometry.dispose();
1230
- });
1231
- _anchorTagObjects.delete(id);
1232
- }
1233
- }
1234
-
1235
- // Add/update anchor/tag objects
1236
- for (const n of visibleNodes) {
1237
- if (!n.payload || (!n.payload._isAnchor && !n.payload._isTag)) continue;
1238
-
1239
- const existing = _anchorTagObjects.get(n.id);
1240
- if (existing) {
1241
- // Already exists — update position
1242
- existing.position.set(n.x || 0, n.y || 0, n.z || 0);
1243
- n.__threeObj = existing; // keep compat for animate loop
1244
- continue;
1245
- }
1246
-
1247
- // Create new anchor/tag Three.js object
1248
- let obj;
1249
- if (n.payload._isAnchor) obj = createAnchorObject(n);
1250
- else if (n.payload._isTag) obj = createTagObject(n);
1251
-
1252
- if (obj) {
1253
- obj.position.set(n.x || 0, n.y || 0, n.z || 0);
1254
- _scene.add(obj);
1255
- _anchorTagObjects.set(n.id, obj);
1256
- n.__threeObj = obj; // compat for animate loop
1257
- }
1258
- }
1259
-
1260
- // Rebuild flat array for fast iteration in animate()
1261
- _anchorTagArray = Array.from(_anchorTagObjects.values());
1262
-
1263
- // Rebuild instance mapping for instanced memory node rendering
1264
- rebuildInstanceMap();
1265
-
1266
- _linkBatchDirty = true;
1267
- _linkPosDirty = true;
1268
-
1269
- // Pin any unpositioned nodes
1270
- for (const n of visibleNodes) {
1271
- if (n.fx == null && n.x != null) { n.fx = n.x; n.fy = n.y; n.fz = n.z; }
1272
- }
1273
-
1274
- schedulePositionSave();
1275
- }
1276
-
1277
- // ═══════════════════════════════════════════
1278
- // LINK VISIBILITY
1279
- // ═══════════════════════════════════════════
1280
- export function applyLinkVisibility() {
1281
- _linkBatchDirty = true;
1282
- _linkPosDirty = true;
1283
- }
1284
-
1285
- let _linksFetching = false;
1286
- export async function setLinkMode(mode) {
1287
- state.linkMode = mode;
1288
- if (mode === 'off') {
1289
- noLinksScaleBoost = 1.4;
1290
- applyLinkVisibility();
1291
- return;
1292
- }
1293
-
1294
- noLinksScaleBoost = 1.0;
1295
-
1296
- // Lazy-load links from server on first enable
1297
- if (state.allLinks.length === 0 && !_linksFetching) {
1298
- _linksFetching = true;
1299
- try {
1300
- const data = await fetchLinks();
1301
- if (data.links) {
1302
- state.allLinks = data.links;
1303
- emit('stats-changed');
1304
- }
1305
- } catch (err) {
1306
- console.error('Failed to fetch links:', err);
1307
- } finally {
1308
- _linksFetching = false;
1309
- }
1310
- }
1311
-
1312
- applyGraphData();
1313
- applyLinkVisibility();
1314
- }
1315
-
1316
- export function setLinkTypeFilter(filter) {
1317
- state.linkTypeFilter = filter;
1318
- applyLinkVisibility();
1319
- }
1320
-
1321
- // ═══════════════════════════════════════════
1322
- // GRAPH REMOVAL SCHEDULING
1323
- // ═══════════════════════════════════════════
1324
- export function scheduleGraphRemoval(delay = 600) {
1325
- _linkBatchDirty = true;
1326
- _linkPosDirty = true;
1327
- if (graphRemovalTimer) clearTimeout(graphRemovalTimer);
1328
- graphRemovalTimer = setTimeout(() => {
1329
- graphRemovalTimer = null;
1330
- applyGraphData();
1331
- emit('stats-changed');
1332
- }, delay);
1333
- }
1334
-
1335
- export function cancelScheduledRemoval() {
1336
- if (graphRemovalTimer) {
1337
- clearTimeout(graphRemovalTimer);
1338
- graphRemovalTimer = null;
1339
- }
1340
- }
1341
-
1342
- // ═══════════════════════════════════════════
1343
- // INTERACTIONS — hover, click, drag
1344
- // ═══════════════════════════════════════════
1345
-
1346
- function _initUIGuards() {
1347
- document.querySelectorAll('.glass, #title-bar, #search-container, #stats-bar').forEach(el => {
1348
- el.addEventListener('pointerenter', () => { _pointerOverUI = true; }, true);
1349
- el.addEventListener('pointerleave', () => { _pointerOverUI = false; }, true);
1350
- });
1351
- }
1352
-
1353
- // ═══════════════════════════════════════════
1354
- // CUSTOM POINTER EVENTS + RAYCASTING
1355
- // Replaces ForceGraph3D's onNodeHover/Click/Drag
1356
- // ═══════════════════════════════════════════
1357
-
1358
- function _raycastMemoryNodes(ray) {
1359
- // O(N) ray-sphere intersection against memory node positions.
1360
- // No scene graph objects — pure math. Returns { node, dist } or null.
1361
- let bestDist = Infinity;
1362
- let bestNode = null;
1363
- const ox = ray.origin.x, oy = ray.origin.y, oz = ray.origin.z;
1364
- const dx = ray.direction.x, dy = ray.direction.y, dz = ray.direction.z;
1365
-
1366
- for (let gi = 0, len = _glowNodeOrder.length; gi < len; gi++) {
1367
- if (_nodeScale[gi] <= 0.01) continue; // hidden
1368
- const node = _glowNodeOrder[gi];
1369
- const radius = _nodeBaseRadius[gi] * _nodeScale[gi] * 1.2; // 1.2 = hit margin
1370
- const cx = node.x || 0, cy = node.y || 0, cz = node.z || 0;
1371
-
1372
- // Ray-sphere intersection (algebraic form)
1373
- const ecx = ox - cx, ecy = oy - cy, ecz = oz - cz;
1374
- const b = ecx * dx + ecy * dy + ecz * dz;
1375
- const c = ecx * ecx + ecy * ecy + ecz * ecz - radius * radius;
1376
- const disc = b * b - c;
1377
- if (disc < 0) continue;
1378
- const dist = -b - Math.sqrt(disc);
1379
- if (dist < 0 || dist >= bestDist) continue;
1380
- bestDist = dist;
1381
- bestNode = node;
1382
- }
1383
- return bestNode ? { node: bestNode, dist: bestDist } : null;
1384
- }
1385
-
1386
- function _pickNode(mouseNDC) {
1387
- // Two-pass picking: anchor/tag objects first (standard Three.js), then memory nodes (ray-sphere)
1388
- _raycaster.setFromCamera(mouseNDC, _camera);
1389
- const ray = _raycaster.ray;
1390
-
1391
- // Pass 1: anchor/tag objects (~50-100 Three.js Groups with PlaneGeometry hitboxes)
1392
- if (_anchorTagArray.length > 0) {
1393
- const hits = _raycaster.intersectObjects(_anchorTagArray, true);
1394
- if (hits.length > 0) {
1395
- let obj = hits[0].object;
1396
- while (obj && !obj.userData.nodeId) obj = obj.parent;
1397
- if (obj && obj.userData.nodeId) {
1398
- const node = _nodeById.get(obj.userData.nodeId);
1399
- if (node) return { node, dist: hits[0].distance };
1400
- }
1401
- }
1402
- }
1403
-
1404
- // Pass 2: memory nodes (ray-sphere math — no scene objects)
1405
- return _raycastMemoryNodes(ray);
1406
- }
1407
-
1408
- let _prevHoveredNode = null;
1409
-
1410
- function _onPointerMove(e) {
1411
- if (_focusPaused || _pointerOverUI) return;
1412
-
1413
- const rect = _graphContainer
1414
- ? _graphContainer.getBoundingClientRect()
1415
- : { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
1416
- _mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
1417
- _mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
1418
-
1419
- if (_drag.active) {
1420
- _handleDragMove(e);
1421
- return;
1422
- }
1423
-
1424
- // Hover detection
1425
- const hit = _pickNode(_mouse);
1426
- const hoveredNode = hit ? hit.node : null;
1427
- if (hoveredNode !== _prevHoveredNode) {
1428
- handleNodeHover(hoveredNode, _prevHoveredNode);
1429
- _prevHoveredNode = hoveredNode;
1430
- }
1431
- }
1432
-
1433
- function _onPointerDown(e) {
1434
- if (_focusPaused || e.button !== 0 || _pointerOverUI) return;
1435
- _pointerDownPos = { x: e.clientX, y: e.clientY };
1436
- _pointerDownTime = performance.now();
1437
-
1438
- const hit = _pickNode(_mouse);
1439
- _pointerDownNode = hit ? hit.node : null;
1440
-
1441
- if (_pointerDownNode) {
1442
- _startDrag(_pointerDownNode, e);
1443
- }
1444
- }
1445
-
1446
- function _onPointerUp(e) {
1447
- if (_focusPaused || e.button !== 0) return;
1448
-
1449
- if (_drag.active) {
1450
- const wasDrag = _pointerDownPos
1451
- ? Math.sqrt(
1452
- (e.clientX - _pointerDownPos.x) ** 2 +
1453
- (e.clientY - _pointerDownPos.y) ** 2
1454
- ) >= 5
1455
- : true;
1456
-
1457
- _endDrag();
1458
-
1459
- // If pointer barely moved, treat as click on the originally picked node
1460
- if (!wasDrag && _pointerDownNode) {
1461
- handleNodeClick(_pointerDownNode, e);
1462
- }
1463
- _pointerDownPos = null;
1464
- _pointerDownNode = null;
1465
- return;
1466
- }
1467
-
1468
- if (!_pointerDownPos) return;
1469
- const dx = e.clientX - _pointerDownPos.x;
1470
- const dy = e.clientY - _pointerDownPos.y;
1471
- const dt = performance.now() - _pointerDownTime;
1472
- const isClick = Math.sqrt(dx * dx + dy * dy) < 5 && dt < 500;
1473
-
1474
- if (isClick) {
1475
- const hit = _pickNode(_mouse);
1476
- if (hit) {
1477
- handleNodeClick(hit.node, e);
1478
- } else {
1479
- handleBackgroundClick();
1480
- }
1481
- }
1482
- _pointerDownPos = null;
1483
- _pointerDownNode = null;
1484
- }
1485
-
1486
- function _startDrag(node, e) {
1487
- // Drag plane: perpendicular to camera, passing through node position
1488
- const nodePos = _dragHit.set(node.x || 0, node.y || 0, node.z || 0);
1489
- const camDir = _camera.getWorldDirection(_mouseDir);
1490
- _dragPlane.setFromNormalAndCoplanarPoint(camDir, nodePos);
1491
-
1492
- const { type, dragSet } = _buildDragSet(node, _graphNodes);
1493
- _drag.active = true;
1494
- _drag.node = node;
1495
- _drag.type = type;
1496
- _drag.dragSet = dragSet;
1497
- _drag.depthOffset.set(0, 0, 0);
1498
- _drag.prevPos = { x: node.x || 0, y: node.y || 0, z: node.z || 0 };
1499
- _instancesDirty = true;
1500
- document.body.style.cursor = 'grabbing';
1501
- _controls.enabled = false; // Disable orbit during drag
1502
- }
1503
-
1504
- function _handleDragMove(e) {
1505
- if (!_drag.active || !_drag.node) return;
1506
-
1507
- _raycaster.setFromCamera(_mouse, _camera);
1508
- if (!_raycaster.ray.intersectPlane(_dragPlane, _dragHit)) return;
1509
-
1510
- const newX = _dragHit.x + _drag.depthOffset.x;
1511
- const newY = _dragHit.y + _drag.depthOffset.y;
1512
- const newZ = _dragHit.z + _drag.depthOffset.z;
1513
- const node = _drag.node;
1514
-
1515
- if (_drag.prevPos) {
1516
- const ddx = newX - _drag.prevPos.x;
1517
- const ddy = newY - _drag.prevPos.y;
1518
- const ddz = newZ - _drag.prevPos.z;
1519
-
1520
- if (ddx !== 0 || ddy !== 0 || ddz !== 0) {
1521
- for (let i = 0, len = _graphNodes.length; i < len; i++) {
1522
- const n = _graphNodes[i];
1523
- if (n === node || !_drag.dragSet.has(n.id)) continue;
1524
- n.x = (n.x || 0) + ddx;
1525
- n.y = (n.y || 0) + ddy;
1526
- n.z = (n.z || 0) + ddz;
1527
- n.fx = n.x; n.fy = n.y; n.fz = n.z;
1528
- // Move anchor/tag Three.js object if exists
1529
- const obj = _anchorTagObjects.get(n.id);
1530
- if (obj) obj.position.set(n.x, n.y, n.z);
1531
- }
1532
- }
1533
- }
1534
-
1535
- node.x = newX; node.y = newY; node.z = newZ;
1536
- node.fx = node.x; node.fy = node.y; node.fz = node.z;
1537
- const nodeObj = _anchorTagObjects.get(node.id);
1538
- if (nodeObj) nodeObj.position.set(node.x, node.y, node.z);
1539
-
1540
- _drag.prevPos = { x: newX, y: newY, z: newZ };
1541
- _linkPosDirty = true;
1542
- _instancesDirty = true;
1543
- }
1544
-
1545
- function _endDrag() {
1546
- if (!_drag.active) return;
1547
- const node = _drag.node;
1548
- if (node) { node.fx = node.x; node.fy = node.y; node.fz = node.z; }
1549
- document.body.style.cursor = state.hoveredNodeId ? 'grab' : 'default';
1550
- _drag.active = false;
1551
- _drag.node = null;
1552
- _drag.type = null;
1553
- _drag.dragSet = new Set();
1554
- _drag.prevPos = null;
1555
- _drag.depthOffset.set(0, 0, 0);
1556
- _controls.enabled = true; // Re-enable orbit
1557
- _linkPosDirty = true;
1558
- _instancesDirty = true;
1559
- schedulePositionSave();
1560
- }
1561
-
1562
- function _initPointerEvents(canvas) {
1563
- canvas.addEventListener('pointermove', _onPointerMove);
1564
- canvas.addEventListener('pointerdown', _onPointerDown);
1565
- canvas.addEventListener('pointerup', _onPointerUp);
1566
- }
1567
-
1568
- // ═══════════════════════════════════════════
1569
-
1570
- function handleNodeHover(node, prevNode) {
1571
- const $tooltip = document.getElementById('tooltip');
1572
- if (_pointerOverUI) {
1573
- $tooltip.classList.remove('visible');
1574
- if ($tooltip._moveHandler) {
1575
- document.removeEventListener('mousemove', $tooltip._moveHandler);
1576
- }
1577
- document.body.style.cursor = 'default';
1578
- return;
1579
- }
1580
- if (_drag.active) {
1581
- document.body.style.cursor = 'grabbing';
1582
- } else {
1583
- document.body.style.cursor = node ? 'grab' : 'default';
1584
- }
1585
- state.hoveredNodeId = node ? node.id : null;
1586
- _instancesDirty = true;
1587
-
1588
- if (node) {
1589
- const cat = node.payload.category;
1590
-
1591
- if (node.payload._isAnchor) {
1592
- document.getElementById('tooltip-category').textContent = cat.toUpperCase();
1593
- document.getElementById('tooltip-category').style.color = catColor(cat);
1594
- const childCount = Object.entries(state.categoryMetadata).filter(([, m]) => m.parent === cat).length;
1595
- document.getElementById('tooltip-preview').textContent = `Parent category \u2022 ${childCount} sub-categories`;
1596
- document.getElementById('tooltip-importance').textContent = '\u2606';
1597
- } else if (node.payload._isTag) {
1598
- document.getElementById('tooltip-category').textContent = cat;
1599
- document.getElementById('tooltip-category').style.color = catColor(cat);
1600
- const memCount = state.allNodes.filter(n => n.payload.category === cat).length;
1601
- document.getElementById('tooltip-preview').textContent = `${memCount} memories`;
1602
- document.getElementById('tooltip-importance').textContent = '\u25cf';
1603
- } else {
1604
- const imp = node.payload.importance || 5;
1605
- const preview = (node.payload.content || '').length > 100
1606
- ? node.payload.content.slice(0, 100) + '...'
1607
- : (node.payload.content || '');
1608
- const catText = node.payload._isOpenClaw ? '[OC] ' + cat : cat;
1609
- document.getElementById('tooltip-category').textContent = catText;
1610
- document.getElementById('tooltip-category').style.color = catColor(cat);
1611
- document.getElementById('tooltip-preview').textContent = preview;
1612
- document.getElementById('tooltip-importance').textContent = '\u2605'.repeat(Math.min(imp, 10));
1613
- }
1614
-
1615
- const moveTooltip = (e) => {
1616
- $tooltip.style.left = (e.clientX + 16) + 'px';
1617
- $tooltip.style.top = (e.clientY + 16) + 'px';
1618
- };
1619
- document.addEventListener('mousemove', moveTooltip);
1620
- $tooltip._moveHandler = moveTooltip;
1621
- $tooltip.classList.add('visible');
1622
- } else {
1623
- $tooltip.classList.remove('visible');
1624
- if ($tooltip._moveHandler) {
1625
- document.removeEventListener('mousemove', $tooltip._moveHandler);
1626
- }
1627
- }
1628
- }
1629
-
1630
- function handleNodeClick(node, event) {
1631
- if (!node || _pointerOverUI) return;
1632
-
1633
- // Anchor nodes: zoom to fit entire category cluster
1634
- if (node.payload._isAnchor) {
1635
- const parentName = node.payload._anchorCategory;
1636
- const gd = graph.graphData();
1637
- const childCats = Object.entries(state.categoryMetadata)
1638
- .filter(([, m]) => m.parent === parentName)
1639
- .map(([name]) => name);
1640
- const treeCats = new Set([parentName, ...childCats]);
1641
- const treeNodes = gd.nodes.filter(n =>
1642
- n.payload && (treeCats.has(n.payload.category) || n.payload._anchorCategory === parentName || (n.payload._tagCategory && treeCats.has(n.payload._tagCategory)))
1643
- );
1644
- if (treeNodes.length === 0) return;
1645
-
1646
- let minX = Infinity, maxX = -Infinity;
1647
- let minY = Infinity, maxY = -Infinity;
1648
- let minZ = Infinity, maxZ = -Infinity;
1649
- for (const n of treeNodes) {
1650
- const x = n.x || 0, y = n.y || 0, z = n.z || 0;
1651
- if (x < minX) minX = x; if (x > maxX) maxX = x;
1652
- if (y < minY) minY = y; if (y > maxY) maxY = y;
1653
- if (z < minZ) minZ = z; if (z > maxZ) maxZ = z;
1654
- }
1655
- const cx = (minX + maxX) / 2, cy = (minY + maxY) / 2, cz = (minZ + maxZ) / 2;
1656
- const span = Math.max(maxX - minX, maxY - minY, maxZ - minZ, 30);
1657
- const dist = span * 1.2 + 40;
1658
- graph.cameraPosition(
1659
- { x: cx + dist * 0.5, y: cy + dist * 0.35, z: cz + dist * 0.5 },
1660
- { x: cx, y: cy, z: cz },
1661
- 1500
1662
- );
1663
- return;
1664
- }
1665
-
1666
- // Tag nodes: zoom to show tag + its memory sphere
1667
- if (node.payload._isTag) {
1668
- const tagCat = node.payload._tagCategory;
1669
- const gd = graph.graphData();
1670
- const tagMems = gd.nodes.filter(n => n.payload && n.payload.category === tagCat && !n.payload._isAnchor && !n.payload._isTag);
1671
- if (tagMems.length > 0) {
1672
- let minX = node.x, maxX = node.x, minY = node.y, maxY = node.y, minZ = node.z, maxZ = node.z;
1673
- for (const n of tagMems) {
1674
- const x = n.x || 0, y = n.y || 0, z = n.z || 0;
1675
- if (x < minX) minX = x; if (x > maxX) maxX = x;
1676
- if (y < minY) minY = y; if (y > maxY) maxY = y;
1677
- if (z < minZ) minZ = z; if (z > maxZ) maxZ = z;
1678
- }
1679
- const cx = (minX + maxX) / 2, cy = (minY + maxY) / 2, cz = (minZ + maxZ) / 2;
1680
- const span = Math.max(maxX - minX, maxY - minY, maxZ - minZ, 30);
1681
- const dist = span * 1.1 + 30;
1682
- graph.cameraPosition(
1683
- { x: cx + dist * 0.5, y: cy + dist * 0.3, z: cz + dist * 0.5 },
1684
- { x: cx, y: cy, z: cz },
1685
- 1500
1686
- );
1687
- } else {
1688
- const dist = gfx.gentleZoom;
1689
- graph.cameraPosition(
1690
- { x: node.x + dist, y: node.y + dist * 0.4, z: node.z + dist },
1691
- { x: node.x, y: node.y, z: node.z },
1692
- 1500
1693
- );
1694
- }
1695
- return;
1696
- }
1697
-
1698
- // Ctrl+Click: toggle multi-select
1699
- if (event && (event.ctrlKey || event.metaKey)) {
1700
- if (state.multiSelected.has(node.id)) {
1701
- state.multiSelected.delete(node.id);
1702
- } else {
1703
- state.multiSelected.add(node.id);
1704
- }
1705
- _instancesDirty = true;
1706
- emit('multiselect:update');
1707
- return;
1708
- }
1709
-
1710
- // Regular click: clear multi-select, navigate
1711
- if (state.multiSelected.size > 0) {
1712
- state.multiSelected.clear();
1713
- _instancesDirty = true;
1714
- emit('multiselect:update');
1715
- }
1716
- navigateToNode(node);
1717
- }
1718
-
1719
- export function navigateToNode(node, { zoom = 'close' } = {}) {
1720
- if (!node) return;
1721
- if (node.payload && (node.payload._isAnchor || node.payload._isTag)) return;
1722
- state.selectedNodeId = node.id;
1723
- _instancesDirty = true;
1724
- storage.setItem(KEYS.SELECTED_NODE, node.id);
1725
-
1726
- // Ensure category is visible
1727
- if (!state.activeCategories.has(node.payload.category)) {
1728
- state.activeCategories.add(node.payload.category);
1729
- emit('categories-changed');
1730
- }
1731
-
1732
- // If focus mode is on, switch focus to the new node
1733
- if (state.focusedNodeId !== null) {
1734
- state.focusedNodeId = node.id;
1735
- applyGraphData();
1736
- emit('stats-changed');
1737
- }
1738
-
1739
- // Camera transition
1740
- const dist = zoom === 'gentle' ? gfx.gentleZoom : gfx.clickZoom;
1741
- graph.cameraPosition(
1742
- { x: node.x + dist, y: node.y + dist * 0.4, z: node.z + dist },
1743
- { x: node.x, y: node.y, z: node.z },
1744
- 1500
1745
- );
1746
-
1747
- emit('node-selected', node);
1748
- }
1749
-
1750
- function handleBackgroundClick() {
1751
- // Don't close detail panel on background click
1752
- }
1753
-
1754
- // ═══════════════════════════════════════════
1755
- // INSTANCED MEMORY NODES — static, dirty-flag
1756
- // ═══════════════════════════════════════════
1757
-
1758
- function _updateMemoryNodesInstanced() {
1759
- const nodeCount = _glowNodeOrder.length;
1760
- if (nodeCount === 0) return;
1761
- if (!_instancesDirty) return;
1762
- _instancesDirty = false;
1763
-
1764
- // Phase 1: compute final state directly (no animation, no lerp)
1765
- for (let gi = 0; gi < nodeCount; gi++) {
1766
- const node = _glowNodeOrder[gi];
1767
- const nodeId = node.id;
1768
-
1769
- const isHovered = nodeId === state.hoveredNodeId;
1770
- const isSelected = nodeId === state.selectedNodeId;
1771
- const isDragMember = _drag.active && _drag.dragSet.has(nodeId);
1772
- const isMultiSelected = state.multiSelected.has(nodeId);
1773
- const isCatHidden = !state.activeCategories.has(node.payload.category);
1774
- const isSearchMatch = state.searchResults !== null && state.searchResults.has(nodeId);
1775
- const isSearchMiss = state.searchResults !== null && !isSearchMatch;
1776
-
1777
- // Opacity — direct target, no interpolation
1778
- let opacity = _nodeBaseOpacity[gi];
1779
- if (isSearchMatch) opacity = 0.85;
1780
- else if (isSearchMiss) opacity = 0;
1781
- if (isCatHidden) opacity = 0;
1782
- if (_drag.active && !isCatHidden) {
1783
- if (isDragMember) opacity = Math.max(opacity, 0.6);
1784
- else opacity *= 0.35;
1785
- }
1786
- if (isHovered) opacity = 0.75;
1787
- if (isSelected) opacity = 0.85;
1788
- if (isMultiSelected) opacity = 0.7;
1789
- _nodeOpacity[gi] = opacity;
1790
-
1791
- // Glow opacity
1792
- const glowMult = isSearchMatch ? 0.95 : 0.85;
1793
- _nodeGlowOpacity[gi] = opacity * glowMult;
1794
-
1795
- // Color — direct set, no interpolation
1796
- if (isMultiSelected) {
1797
- _nodeColorR[gi] = _MULTI_SELECT_BLUE.r;
1798
- _nodeColorG[gi] = _MULTI_SELECT_BLUE.g;
1799
- _nodeColorB[gi] = _MULTI_SELECT_BLUE.b;
1800
- } else {
1801
- _nodeColorR[gi] = _nodeBaseColorR[gi];
1802
- _nodeColorG[gi] = _nodeBaseColorG[gi];
1803
- _nodeColorB[gi] = _nodeBaseColorB[gi];
1804
- }
1805
-
1806
- // Scale — direct target, no interpolation
1807
- let scale = 1.0;
1808
- if (isCatHidden || isSearchMiss) scale = 0;
1809
- else if (isSearchMatch) scale = 1.8;
1810
- if (isSelected) scale = 2.0;
1811
- else if (isMultiSelected) scale = 1.5;
1812
- else if (isHovered) scale = 1.6;
1813
- scale *= noLinksScaleBoost;
1814
- _nodeScale[gi] = scale;
1815
-
1816
- // Memory nodes have no Three.js object — raycasting uses _nodeScale[] directly
1817
- }
1818
-
1819
- // Phase 2: compose instance matrices and upload GPU attributes
1820
- const tiers = [_wireInstLow, _wireInstMed, _wireInstHigh];
1821
- let globalOffset = 0;
1822
-
1823
- for (let t = 0; t < 3; t++) {
1824
- const inst = tiers[t];
1825
- const tierLen = _tierNodes[t].length;
1826
- if (!inst || tierLen === 0) { globalOffset += tierLen; continue; }
1827
-
1828
- const colorArr = inst.geometry.attributes.instanceColor.array;
1829
- const opacityArr = inst.geometry.attributes.instanceOpacity.array;
1830
-
1831
- for (let i = 0; i < tierLen; i++) {
1832
- const gi = globalOffset + i;
1833
- const node = _tierNodes[t][i];
1834
- const scale = _nodeScale[gi] * _nodeBaseRadius[gi];
1835
-
1836
- // Compose matrix: position + uniform scale (no rotation)
1837
- _instPos.set(node.x || 0, node.y || 0, node.z || 0);
1838
- _instScaleV.set(scale, scale, scale);
1839
- _instMatrix.compose(_instPos, _identityQuat, _instScaleV);
1840
- inst.setMatrixAt(i, _instMatrix);
1841
-
1842
- // Color
1843
- const ci3 = i * 3;
1844
- colorArr[ci3] = _nodeColorR[gi];
1845
- colorArr[ci3 + 1] = _nodeColorG[gi];
1846
- colorArr[ci3 + 2] = _nodeColorB[gi];
1847
-
1848
- // Opacity
1849
- opacityArr[i] = _nodeOpacity[gi];
1850
- }
1851
-
1852
- inst.instanceMatrix.needsUpdate = true;
1853
- inst.geometry.attributes.instanceColor.needsUpdate = true;
1854
- inst.geometry.attributes.instanceOpacity.needsUpdate = true;
1855
-
1856
- globalOffset += tierLen;
1857
- }
1858
-
1859
- // Glow Points: write position + color + opacity + size
1860
- if (_glowPoints && nodeCount > 0) {
1861
- const posArr = _glowPointsGeo.attributes.position.array;
1862
- const colArr = _glowPointsGeo.attributes.glowColor.array;
1863
- const opArr = _glowPointsGeo.attributes.glowOpacity.array;
1864
- const sizeArr = _glowPointsGeo.attributes.glowSize.array;
1865
-
1866
- for (let gi = 0; gi < nodeCount; gi++) {
1867
- const node = _glowNodeOrder[gi];
1868
- const gi3 = gi * 3;
1869
-
1870
- posArr[gi3] = node.x || 0;
1871
- posArr[gi3 + 1] = node.y || 0;
1872
- posArr[gi3 + 2] = node.z || 0;
1873
-
1874
- colArr[gi3] = _nodeColorR[gi];
1875
- colArr[gi3 + 1] = _nodeColorG[gi];
1876
- colArr[gi3 + 2] = _nodeColorB[gi];
1877
-
1878
- opArr[gi] = _nodeGlowOpacity[gi];
1879
- sizeArr[gi] = _nodeBaseRadius[gi] * _nodeScale[gi] * 1.4;
1880
- }
1881
-
1882
- _glowPointsGeo.attributes.position.needsUpdate = true;
1883
- _glowPointsGeo.attributes.glowColor.needsUpdate = true;
1884
- _glowPointsGeo.attributes.glowOpacity.needsUpdate = true;
1885
- _glowPointsGeo.attributes.glowSize.needsUpdate = true;
1886
- }
1887
- }
1888
-
1889
-
1890
- // ═══════════════════════════════════════════
1891
- // ANIMATION LOOP
1892
- // ═══════════════════════════════════════════
1893
- function animate() {
1894
- animFrameId = requestAnimationFrame(animate);
1895
- const time = performance.now() * 0.001;
1896
-
1897
- TWEEN.update();
1898
-
1899
- // Update wireframe orb shader time uniform (Fresnel shimmer)
1900
- if (_wireInstLow) _wireInstLow.material.uniforms.uTime.value = time;
1901
- if (_wireInstMed) _wireInstMed.material.uniforms.uTime.value = time;
1902
- if (_wireInstHigh) _wireInstHigh.material.uniforms.uTime.value = time;
1903
-
1904
- // WASD camera movement — delegated to camera module via event
1905
- emit('camera-tick');
1906
-
1907
- // Update 3D mouse position via raycasting (skip when mouse hasn't moved)
1908
- if (_mouseMoved) {
1909
- updateMouse3D();
1910
- _mouseMoved = false;
1911
- }
1912
-
1913
- // Floor effect uniforms (updated by background module listening to 'animate-tick')
1914
- emit('animate-tick', { time, graph });
1915
-
1916
- // ── Node pass ──
1917
- if (graph) {
1918
- const _cam = _camera;
1919
-
1920
- // Build frustum once per frame
1921
- _cam.updateMatrixWorld();
1922
- _projScreenMatrix.multiplyMatrices(_cam.projectionMatrix, _cam.matrixWorldInverse);
1923
- _frustum.setFromProjectionMatrix(_projScreenMatrix);
1924
- _frustumPadded.copy(_frustum);
1925
- for (let _pi = 0; _pi < 6; _pi++) _frustumPadded.planes[_pi].constant += 60;
1926
-
1927
- // ── Pass 1: Anchor/Tag nodes only (~50-100 objects, not 3500) ──
1928
- for (let _ni = 0, _nlen = _anchorTagArray.length; _ni < _nlen; _ni++) {
1929
- const obj = _anchorTagArray[_ni];
1930
- if (!obj || !obj.userData || !obj.userData.nodeId) continue;
1931
-
1932
- const dot = obj.userData.dot;
1933
- const label = obj.userData.label;
1934
- const phase = obj.userData.phase || 0;
1935
- const isCatHidden = !state.activeCategories.has(obj.userData.category);
1936
- const isHovered = obj.userData.nodeId === state.hoveredNodeId;
1937
- const isSelected = obj.userData.nodeId === state.selectedNodeId;
1938
- const isMultiSelected = state.multiSelected.has(obj.userData.nodeId);
1939
-
1940
- // Frustum culling
1941
- obj.getWorldPosition(_worldPos);
1942
- let _cullZone = 0;
1943
- if (!_frustum.containsPoint(_worldPos)) {
1944
- _cullZone = _frustumPadded.containsPoint(_worldPos) ? 1 : 2;
1945
- }
1946
- if (isHovered || isSelected || (_drag.active && _drag.dragSet.has(obj.userData.nodeId))) {
1947
- _cullZone = 0;
1948
- }
1949
-
1950
- // Zone 2: fully outside — decay to invisible, then skip entirely
1951
- if (_cullZone === 2) {
1952
- // Already fully faded — skip all work
1953
- if (obj.userData._currentScale <= 0.01) {
1954
- const dotOp = dot ? dot.material.opacity : 0;
1955
- const labelOp = label ? (label.material.uniforms ? label.material.uniforms.uOpacity.value : label.material.opacity) : 0;
1956
- const glowOp = obj.userData.glow ? obj.userData.glow.material.opacity : 0;
1957
- if (dotOp === 0 && labelOp === 0 && glowOp === 0) continue;
1958
- }
1959
- if (dot) {
1960
- dot.material.opacity *= 0.85;
1961
- if (dot.material.opacity < 0.005) dot.material.opacity = 0;
1962
- }
1963
- if (label) {
1964
- if (label.material.uniforms) {
1965
- label.material.uniforms.uOpacity.value *= 0.85;
1966
- if (label.material.uniforms.uOpacity.value < 0.005) label.material.uniforms.uOpacity.value = 0;
1967
- } else {
1968
- label.material.opacity *= 0.85;
1969
- if (label.material.opacity < 0.005) label.material.opacity = 0;
1970
- }
1971
- }
1972
- const _glowCull = obj.userData.glow;
1973
- if (_glowCull) {
1974
- _glowCull.material.opacity *= 0.85;
1975
- if (_glowCull.material.opacity < 0.005) _glowCull.material.opacity = 0;
1976
- }
1977
- if (obj.userData._currentScale > 0.01) {
1978
- obj.userData._currentScale *= 0.9;
1979
- obj.scale.setScalar(obj.userData._currentScale);
1980
- }
1981
- continue;
1982
- }
1983
-
1984
- // Mouse proximity
1985
- let mouseProx = 0;
1986
- if (_cullZone === 0 && _mouse3DValid && _mouse3D.lengthSq() > 0) {
1987
- const mouseDist = _mouse3D.distanceTo(_worldPos);
1988
- mouseProx = 1 - Math.min(mouseDist / PLEXUS_RADIUS, 1);
1989
- mouseProx = mouseProx * mouseProx;
1990
- }
1991
-
1992
- const breathe = 1 + Math.sin(time * 0.5 + phase) * 0.03;
1993
-
1994
- // ── Anchor nodes ──
1995
- if (obj.userData.isAnchor) {
1996
- const baseOp = obj.userData.baseOpacity;
1997
- let dotTarget = baseOp + mouseProx * 0.2;
1998
- let labelTarget = 1.0;
1999
- if (!state.labelsVisible) labelTarget = 0;
2000
- if (isCatHidden) { dotTarget = 0; labelTarget = 0; }
2001
- else if (state.searchResults !== null && !state.searchResults.has(obj.userData.nodeId)) {
2002
- dotTarget = 0; labelTarget = 0;
2003
- }
2004
- if (_drag.active && !isCatHidden) {
2005
- if (_drag.dragSet.has(obj.userData.nodeId)) dotTarget = Math.max(dotTarget, 0.9);
2006
- else { dotTarget *= 0.5; labelTarget *= 0.85; }
2007
- }
2008
- if (isHovered) { dotTarget = 1.0; labelTarget = 1.0; }
2009
- if (isSelected) dotTarget = 1.0;
2010
- if (_cullZone === 1) { dotTarget *= 0.5; }
2011
-
2012
- const fade = isCatHidden ? 0.15 : 0.2;
2013
- if (dot) dot.material.opacity += (dotTarget * breathe - dot.material.opacity) * fade;
2014
- if (label) {
2015
- if (label.material.uniforms) {
2016
- label.material.uniforms.uOpacity.value += (labelTarget - label.material.uniforms.uOpacity.value) * fade;
2017
- // Floor: visible labels never go below 0.9 opacity
2018
- if (_cullZone === 0 && labelTarget > 0 && label.material.uniforms.uOpacity.value < 0.9) {
2019
- label.material.uniforms.uOpacity.value = 0.9;
2020
- }
2021
- } else {
2022
- label.material.opacity += (labelTarget - label.material.opacity) * fade;
2023
- }
2024
- // Billboard: face camera
2025
- label.quaternion.copy(_cam.quaternion);
2026
- }
2027
-
2028
- if (label && obj.userData.baseLabelScale) {
2029
- const camDist = _cam.position.distanceTo(_worldPos);
2030
- const scaleFactor = Math.max(1.5, Math.min(8.0, camDist / 80)) * state.labelSizeMultiplier;
2031
- const bls = obj.userData.baseLabelScale;
2032
- label.scale.set(bls.x * scaleFactor, bls.y * scaleFactor, 1);
2033
- }
2034
-
2035
- let targetScale = isCatHidden ? 0 : breathe;
2036
- if (isHovered) targetScale *= 1.15;
2037
- if (obj.userData._currentScale == null) obj.userData._currentScale = 0.01;
2038
- obj.userData._currentScale += (targetScale - obj.userData._currentScale) * 0.1;
2039
- obj.scale.setScalar(obj.userData._currentScale);
2040
- continue;
2041
- }
2042
-
2043
- // ── Tag nodes ──
2044
- if (obj.userData.isTag) {
2045
- const baseOp = obj.userData.baseOpacity;
2046
- let dotTarget = baseOp + mouseProx * 0.3;
2047
- let labelTarget = 1.0;
2048
- if (!state.labelsVisible) labelTarget = 0;
2049
-
2050
- if (isCatHidden) { dotTarget = 0; labelTarget = 0; }
2051
- else if (state.searchResults !== null && !state.searchResults.has(obj.userData.nodeId)) {
2052
- dotTarget = 0; labelTarget = 0;
2053
- }
2054
- if (_drag.active && !isCatHidden) {
2055
- if (_drag.dragSet.has(obj.userData.nodeId)) dotTarget = Math.max(dotTarget, 0.8);
2056
- else { dotTarget *= 0.4; labelTarget *= 0.85; }
2057
- }
2058
- if (isHovered) { dotTarget = 1.0; labelTarget = 1.0; }
2059
- if (isSelected) dotTarget = 1.0;
2060
- if (_cullZone === 1) { dotTarget *= 0.5; }
2061
-
2062
- const fade = isCatHidden ? 0.15 : 0.2;
2063
- if (dot) dot.material.opacity += (dotTarget * breathe - dot.material.opacity) * fade;
2064
- if (label) {
2065
- if (label.material.uniforms) {
2066
- label.material.uniforms.uOpacity.value += (labelTarget - label.material.uniforms.uOpacity.value) * fade;
2067
- // Floor: visible labels never go below 0.9 opacity
2068
- if (_cullZone === 0 && labelTarget > 0 && label.material.uniforms.uOpacity.value < 0.9) {
2069
- label.material.uniforms.uOpacity.value = 0.9;
2070
- }
2071
- } else {
2072
- label.material.opacity += (labelTarget - label.material.opacity) * fade;
2073
- }
2074
- // Billboard: face camera
2075
- label.quaternion.copy(_cam.quaternion);
2076
- }
2077
-
2078
- if (label && obj.userData.baseLabelScale) {
2079
- const camDist = _cam.position.distanceTo(_worldPos);
2080
- const scaleFactor = Math.max(1.2, Math.min(6.0, camDist / 60)) * state.labelSizeMultiplier;
2081
- const bls = obj.userData.baseLabelScale;
2082
- label.scale.set(bls.x * scaleFactor, bls.y * scaleFactor, 1);
2083
- label.position.y = (obj.userData.baseLabelY || obj.userData.baseRadius * 1.0) * scaleFactor;
2084
- }
2085
-
2086
- let targetScale = isCatHidden ? 0 : breathe * (1 + mouseProx * 0.1);
2087
- if (isHovered) targetScale *= 1.1;
2088
- if (obj.userData._currentScale == null) obj.userData._currentScale = 0.01;
2089
- obj.userData._currentScale += (targetScale - obj.userData._currentScale) * 0.1;
2090
- obj.scale.setScalar(obj.userData._currentScale);
2091
- continue;
2092
- }
2093
-
2094
- }
2095
-
2096
- // ── Pass 2: Memory nodes (instanced rendering) ──
2097
- _updateMemoryNodesInstanced();
2098
-
2099
- // ── LINK BATCH — single draw call ──
2100
- if (_linkBatch) {
2101
- if (_linkBatchDirty && _nodeById.size > 0) {
2102
- _batchLinks.length = 0;
2103
- if (state.linkMode !== 'off') {
2104
- const grey = { r: 0.45, g: 0.45, b: 0.45 };
2105
- const colorCache = new Map();
2106
- function _getMuted(cat) {
2107
- let c = colorCache.get(cat);
2108
- if (!c) {
2109
- const base = new THREE.Color(catColor(cat));
2110
- c = { r: base.r + (grey.r - base.r) * 0.5, g: base.g + (grey.g - base.g) * 0.5, b: base.b + (grey.b - base.b) * 0.5 };
2111
- colorCache.set(cat, c);
2112
- }
2113
- return c;
2114
- }
2115
- const cols = _linkBatchColors;
2116
- let ci = 0;
2117
- for (let li = 0, ll = _visualLinks.length; li < ll; li++) {
2118
- const link = _visualLinks[li];
2119
- if (state.linkMode === 'intra' && link._crossCategory) continue;
2120
- if (state.linkTypeFilter !== 'all' && (!link.types || !link.types.includes(state.linkTypeFilter))) continue;
2121
- const srcId = link.source.id || link.source;
2122
- const tgtId = link.target.id || link.target;
2123
- const srcNode = _nodeById.get(srcId);
2124
- const tgtNode = _nodeById.get(tgtId);
2125
- if (!srcNode || !tgtNode) continue;
2126
- const srcCat = srcNode.payload ? srcNode.payload.category : null;
2127
- const tgtCat = tgtNode.payload ? tgtNode.payload.category : null;
2128
- if (srcCat && !state.activeCategories.has(srcCat)) continue;
2129
- if (tgtCat && !state.activeCategories.has(tgtCat)) continue;
2130
- // Hide links where both endpoints are not search matches
2131
- if (state.searchResults !== null) {
2132
- const srcMatch = state.searchResults.has(srcId);
2133
- const tgtMatch = state.searchResults.has(tgtId);
2134
- if (!srcMatch && !tgtMatch) continue;
2135
- }
2136
- if (ci + 6 > cols.length) break;
2137
- link._srcNode = srcNode;
2138
- link._tgtNode = tgtNode;
2139
- _batchLinks.push(link);
2140
- const sc = _getMuted(srcNode.payload ? srcNode.payload.category : '_fallback');
2141
- const tc = _getMuted(tgtNode.payload ? tgtNode.payload.category : '_fallback');
2142
- cols[ci] = sc.r; cols[ci + 1] = sc.g; cols[ci + 2] = sc.b;
2143
- cols[ci + 3] = tc.r; cols[ci + 4] = tc.g; cols[ci + 5] = tc.b;
2144
- ci += 6;
2145
- }
2146
- _linkBatchGeo.attributes.color.needsUpdate = true;
2147
- }
2148
- _linkBatchDirty = false;
2149
- }
2150
-
2151
- // Update positions only when nodes have moved (drag, layout change)
2152
- if (_linkPosDirty) {
2153
- const bl = _batchLinks;
2154
- const blen = bl.length;
2155
- if (blen > 0) {
2156
- const pos = _linkBatchPositions;
2157
- let pi = 0;
2158
- for (let i = 0; i < blen; i++) {
2159
- const s = bl[i]._srcNode, t = bl[i]._tgtNode;
2160
- pos[pi] = s.x; pos[pi + 1] = s.y; pos[pi + 2] = s.z;
2161
- pos[pi + 3] = t.x; pos[pi + 4] = t.y; pos[pi + 5] = t.z;
2162
- pi += 6;
2163
- }
2164
- _linkBatchGeo.attributes.position.needsUpdate = true;
2165
- _linkBatchGeo.setDrawRange(0, blen * 2);
2166
- } else {
2167
- _linkBatchGeo.setDrawRange(0, 0);
2168
- }
2169
- _linkPosDirty = false;
2170
- }
2171
-
2172
- // Sync opacity from GFX slider
2173
- const targetOp = gfx.linkOpacity || 0.12;
2174
- if (_linkBatch.material.opacity !== targetOp) _linkBatch.material.opacity = targetOp;
2175
- }
2176
- }
2177
-
2178
- // ── Render ── (single render loop — no more ForceGraph3D internal loop)
2179
- if (_controls) _controls.update(); // damping
2180
- if (_composer) {
2181
- _composer.render();
2182
- } else if (_renderer && _scene && _camera) {
2183
- _renderer.render(_scene, _camera);
2184
- }
2185
- }
2186
-
2187
- // ═══════════════════════════════════════════
2188
- // GRAPH INITIALIZATION
2189
- // ═══════════════════════════════════════════
2190
-
2191
- /**
2192
- * Initialize the 3D graph with raw Three.js (no ForceGraph3D dependency).
2193
- * @param {HTMLElement} container The DOM element to render into (e.g. #graph-container)
2194
- * @param {Object} [options] Optional callbacks
2195
- * @param {Function} [options.onApplyBgTheme] Called after graph is built to apply background
2196
- * @returns {Object} The graph proxy object
2197
- */
2198
- export function initGraph(container, options = {}) {
2199
- _graphContainer = container;
2200
-
2201
- // Initialize mouse tracking and UI guards
2202
- _initMouseTracking();
2203
- _initUIGuards();
2204
-
2205
- // ── 1. Renderer ──
2206
- _renderer = new THREE.WebGLRenderer({
2207
- antialias: true,
2208
- powerPreference: 'high-performance',
2209
- alpha: false,
2210
- });
2211
- _renderer.setPixelRatio(window.devicePixelRatio);
2212
- _renderer.setSize(container.offsetWidth, container.offsetHeight);
2213
- _renderer.setClearColor(new THREE.Color('#050505'));
2214
- _renderer.toneMapping = THREE.NoToneMapping;
2215
- _renderer.sortObjects = false;
2216
- _renderer.info.autoReset = false;
2217
- container.appendChild(_renderer.domElement);
2218
-
2219
- // ── 2. Scene ──
2220
- _scene = new THREE.Scene();
2221
-
2222
- // ── 3. Camera ──
2223
- _camera = new THREE.PerspectiveCamera(
2224
- 70,
2225
- container.offsetWidth / container.offsetHeight,
2226
- 0.1,
2227
- 50000,
2228
- );
2229
- _camera.position.set(0, 600, 1400);
2230
-
2231
- // ── 4. OrbitControls ──
2232
- _controls = new OrbitControls(_camera, _renderer.domElement);
2233
- _controls.enableDamping = true;
2234
- _controls.dampingFactor = 0.08;
2235
-
2236
- // ── 5. EffectComposer + RenderPass ──
2237
- _composer = new EffectComposer(_renderer);
2238
- _composer.addPass(new RenderPass(_scene, _camera));
2239
-
2240
- // ── 6. Resize handler ──
2241
- window.addEventListener('resize', _onResize);
2242
-
2243
- // ── 7. Assign proxy as `graph` ──
2244
- graph = graphProxy;
2245
-
2246
- // ── 8. Pointer events for hover/click/drag (custom raycasting) ──
2247
- _initPointerEvents(_renderer.domElement);
2248
-
2249
- // Init instanced rendering for memory nodes (MUST be before applyGraphData
2250
- // so rebuildInstanceMap() can set instance counts on the already-created meshes)
2251
- initInstancedRendering();
2252
-
2253
- // Apply data (layout is computed, positions are pinned)
2254
- applyGraphData();
2255
-
2256
- // One-time reset: clear saved positions for new layout version
2257
- if (storage.getItem(KEYS.LAYOUT_VERSION) !== 'v6-polished') {
2258
- try { storage.removeItem(_posStorageKey); } catch (_) {}
2259
- storage.setItem(KEYS.LAYOUT_VERSION, 'v6-polished');
2260
- }
2261
-
2262
- // Apply link visibility
2263
- applyLinkVisibility();
2264
-
2265
- // Bloom post-processing (half resolution for performance)
2266
- if (gfx.bloomEnabled !== false) {
2267
- _bloomPass = new UnrealBloomPass(
2268
- new THREE.Vector2(Math.floor(container.offsetWidth / 2), Math.floor(container.offsetHeight / 2)),
2269
- 0.5, // strength
2270
- 0.4, // radius
2271
- 1.0 // threshold — only orbs (2.5x output) bloom, not labels
2272
- );
2273
- _composer.addPass(_bloomPass);
2274
- }
2275
-
2276
- // OutputPass: converts linear→sRGB for correct display brightness
2277
- _composer.addPass(new OutputPass());
2278
-
2279
- // Apply background theme
2280
- if (options.onApplyBgTheme) {
2281
- options.onApplyBgTheme(gfx.bgTheme || 'deep-grid');
2282
- }
2283
-
2284
- // Init batch link renderer
2285
- initLinkBatch();
2286
-
2287
- // Start animation loop
2288
- animate();
2289
-
2290
- return graph;
2291
- }
2292
-
2293
- // ═══════════════════════════════════════════
2294
- // RESIZE HANDLER
2295
- // ═══════════════════════════════════════════
2296
- function _onResize() {
2297
- if (!_graphContainer || !_camera || !_renderer || !_composer) return;
2298
- const w = _graphContainer.offsetWidth;
2299
- const h = _graphContainer.offsetHeight;
2300
- _camera.aspect = w / h;
2301
- _camera.updateProjectionMatrix();
2302
- _renderer.setSize(w, h);
2303
- _composer.setSize(w, h);
2304
- if (_bloomPass) {
2305
- _bloomPass.resolution.set(Math.floor(w / 2), Math.floor(h / 2));
2306
- }
2307
- }
2308
-
2309
- // ═══════════════════════════════════════════
2310
- // PUBLIC API
2311
- // ═══════════════════════════════════════════
2312
-
2313
- /** Returns the graph proxy (or null before init). */
2314
- export function getGraph() {
2315
- return graph;
2316
- }
2317
-
2318
- /** Returns the bloom pass (or null before init). */
2319
- export function getBloomPass() {
2320
- return _bloomPass;
2321
- }
2322
-
2323
- /** Returns current visual links array. */
2324
- export function getVisualLinks() {
2325
- return _visualLinks;
2326
- }
2327
-
2328
- /** Returns the node-by-id Map. */
2329
- export function getNodeById() {
2330
- return _nodeById;
2331
- }
2332
-
2333
- /** Mark the link batch as dirty (force rebuild on next frame). */
2334
- export function markLinksDirty() {
2335
- _linkBatchDirty = true;
2336
- _linkPosDirty = true;
2337
- }
2338
-
2339
- /** Returns the drag state object (read-only). */
2340
- export function getDragState() {
2341
- return _drag;
2342
- }
2343
-
2344
- /** Stop the animation loop. */
2345
- export function stopAnimation() {
2346
- if (animFrameId) {
2347
- cancelAnimationFrame(animFrameId);
2348
- animFrameId = null;
2349
- }
2350
- }
2351
-
2352
- /** Restart the animation loop after stopping. */
2353
- export function startAnimation() {
2354
- if (!animFrameId) animate();
2355
- }
2356
-
2357
- /** Pause all interaction (focus mode — zero resource consumption). */
2358
- export function pauseInteraction() {
2359
- _focusPaused = true;
2360
- if (_controls) _controls.enabled = false;
2361
- }
2362
-
2363
- /** Resume interaction after focus mode exit. */
2364
- export function resumeInteraction() {
2365
- _focusPaused = false;
2366
- if (_controls) _controls.enabled = true;
2367
- }
2368
-
2369
- /** Clear saved node positions from localStorage. */
2370
- export function clearSavedPositions() {
2371
- try { storage.removeItem(_posStorageKey); } catch (_) {}
2372
- }
2373
-
2374
- /** Recompute layout from scratch (no saved positions). */
2375
- export function resetLayout() {
2376
- clearSavedPositions();
2377
- applyGraphData();
2378
- }
2379
-
2380
- /** Update bloom pass parameters. */
2381
- export function setBloomParams(strength, threshold, radius) {
2382
- if (_bloomPass) {
2383
- if (strength !== undefined) _bloomPass.strength = strength;
2384
- if (threshold !== undefined) _bloomPass.threshold = threshold;
2385
- if (radius !== undefined) _bloomPass.radius = radius;
2386
- }
2387
- }
2388
-
2389
- /** Enable or disable bloom post-processing at runtime. */
2390
- export function setBloomEnabled(enabled) {
2391
- if (_bloomPass) {
2392
- _bloomPass.enabled = enabled;
2393
- }
2394
- }
2395
-
2396
- /** Returns the noLinksScaleBoost value (used by external animation code). */
2397
- export function getNoLinksScaleBoost() {
2398
- return noLinksScaleBoost;
2399
- }