@nex-ai/nex 0.1.65 → 0.2.1

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 (529) hide show
  1. package/README.md +190 -263
  2. package/bin/nex-mcp.js +50 -0
  3. package/bin/nex.js +53 -0
  4. package/package.json +15 -36
  5. package/dist/agent/adoption.d.ts +0 -23
  6. package/dist/agent/adoption.js +0 -87
  7. package/dist/agent/adoption.js.map +0 -1
  8. package/dist/agent/gossip.d.ts +0 -17
  9. package/dist/agent/gossip.js +0 -48
  10. package/dist/agent/gossip.js.map +0 -1
  11. package/dist/agent/loop.d.ts +0 -59
  12. package/dist/agent/loop.js +0 -389
  13. package/dist/agent/loop.js.map +0 -1
  14. package/dist/agent/queues.d.ts +0 -16
  15. package/dist/agent/queues.js +0 -44
  16. package/dist/agent/queues.js.map +0 -1
  17. package/dist/agent/session-store.d.ts +0 -21
  18. package/dist/agent/session-store.js +0 -96
  19. package/dist/agent/session-store.js.map +0 -1
  20. package/dist/agent/templates.d.ts +0 -5
  21. package/dist/agent/templates.js +0 -55
  22. package/dist/agent/templates.js.map +0 -1
  23. package/dist/agent/tools.d.ts +0 -25
  24. package/dist/agent/tools.js +0 -238
  25. package/dist/agent/tools.js.map +0 -1
  26. package/dist/agent/types.d.ts +0 -59
  27. package/dist/agent/types.js +0 -5
  28. package/dist/agent/types.js.map +0 -1
  29. package/dist/calendar/scheduler.d.ts +0 -32
  30. package/dist/calendar/scheduler.js +0 -178
  31. package/dist/calendar/scheduler.js.map +0 -1
  32. package/dist/calendar/store.d.ts +0 -15
  33. package/dist/calendar/store.js +0 -50
  34. package/dist/calendar/store.js.map +0 -1
  35. package/dist/calendar/types.d.ts +0 -17
  36. package/dist/calendar/types.js +0 -5
  37. package/dist/calendar/types.js.map +0 -1
  38. package/dist/chat/channel.d.ts +0 -20
  39. package/dist/chat/channel.js +0 -84
  40. package/dist/chat/channel.js.map +0 -1
  41. package/dist/chat/message-store.d.ts +0 -18
  42. package/dist/chat/message-store.js +0 -82
  43. package/dist/chat/message-store.js.map +0 -1
  44. package/dist/chat/router.d.ts +0 -17
  45. package/dist/chat/router.js +0 -65
  46. package/dist/chat/router.js.map +0 -1
  47. package/dist/chat/suggested-responses.d.ts +0 -6
  48. package/dist/chat/suggested-responses.js +0 -99
  49. package/dist/chat/suggested-responses.js.map +0 -1
  50. package/dist/chat/types.d.ts +0 -28
  51. package/dist/chat/types.js +0 -5
  52. package/dist/chat/types.js.map +0 -1
  53. package/dist/cli.d.ts +0 -5
  54. package/dist/cli.js +0 -20
  55. package/dist/cli.js.map +0 -1
  56. package/dist/commands/attribute.d.ts +0 -4
  57. package/dist/commands/attribute.js +0 -75
  58. package/dist/commands/attribute.js.map +0 -1
  59. package/dist/commands/config-cmd.d.ts +0 -4
  60. package/dist/commands/config-cmd.js +0 -53
  61. package/dist/commands/config-cmd.js.map +0 -1
  62. package/dist/commands/context.d.ts +0 -4
  63. package/dist/commands/context.js +0 -167
  64. package/dist/commands/context.js.map +0 -1
  65. package/dist/commands/dispatch.d.ts +0 -44
  66. package/dist/commands/dispatch.js +0 -1544
  67. package/dist/commands/dispatch.js.map +0 -1
  68. package/dist/commands/graph.d.ts +0 -5
  69. package/dist/commands/graph.js +0 -77
  70. package/dist/commands/graph.js.map +0 -1
  71. package/dist/commands/init.d.ts +0 -49
  72. package/dist/commands/init.js +0 -319
  73. package/dist/commands/init.js.map +0 -1
  74. package/dist/commands/insight.d.ts +0 -4
  75. package/dist/commands/insight.js +0 -39
  76. package/dist/commands/insight.js.map +0 -1
  77. package/dist/commands/integrate.d.ts +0 -4
  78. package/dist/commands/integrate.js +0 -361
  79. package/dist/commands/integrate.js.map +0 -1
  80. package/dist/commands/list-job.d.ts +0 -4
  81. package/dist/commands/list-job.js +0 -41
  82. package/dist/commands/list-job.js.map +0 -1
  83. package/dist/commands/list.d.ts +0 -4
  84. package/dist/commands/list.js +0 -148
  85. package/dist/commands/list.js.map +0 -1
  86. package/dist/commands/note.d.ts +0 -4
  87. package/dist/commands/note.js +0 -77
  88. package/dist/commands/note.js.map +0 -1
  89. package/dist/commands/object.d.ts +0 -4
  90. package/dist/commands/object.js +0 -78
  91. package/dist/commands/object.js.map +0 -1
  92. package/dist/commands/parse-input.d.ts +0 -5
  93. package/dist/commands/parse-input.js +0 -37
  94. package/dist/commands/parse-input.js.map +0 -1
  95. package/dist/commands/record.d.ts +0 -4
  96. package/dist/commands/record.js +0 -126
  97. package/dist/commands/record.js.map +0 -1
  98. package/dist/commands/register.d.ts +0 -4
  99. package/dist/commands/register.js +0 -23
  100. package/dist/commands/register.js.map +0 -1
  101. package/dist/commands/relationship.d.ts +0 -4
  102. package/dist/commands/relationship.js +0 -80
  103. package/dist/commands/relationship.js.map +0 -1
  104. package/dist/commands/scan.d.ts +0 -4
  105. package/dist/commands/scan.js +0 -111
  106. package/dist/commands/scan.js.map +0 -1
  107. package/dist/commands/search.d.ts +0 -4
  108. package/dist/commands/search.js +0 -62
  109. package/dist/commands/search.js.map +0 -1
  110. package/dist/commands/session.d.ts +0 -4
  111. package/dist/commands/session.js +0 -31
  112. package/dist/commands/session.js.map +0 -1
  113. package/dist/commands/setup.d.ts +0 -25
  114. package/dist/commands/setup.js +0 -584
  115. package/dist/commands/setup.js.map +0 -1
  116. package/dist/commands/task.d.ts +0 -4
  117. package/dist/commands/task.js +0 -140
  118. package/dist/commands/task.js.map +0 -1
  119. package/dist/commands/workspace.d.ts +0 -8
  120. package/dist/commands/workspace.js +0 -251
  121. package/dist/commands/workspace.js.map +0 -1
  122. package/dist/index.d.ts +0 -9
  123. package/dist/index.js +0 -142
  124. package/dist/index.js.map +0 -1
  125. package/dist/lib/capture-filter.d.ts +0 -9
  126. package/dist/lib/capture-filter.js +0 -14
  127. package/dist/lib/capture-filter.js.map +0 -1
  128. package/dist/lib/client.d.ts +0 -20
  129. package/dist/lib/client.js +0 -160
  130. package/dist/lib/client.js.map +0 -1
  131. package/dist/lib/compounding-worker.d.ts +0 -2
  132. package/dist/lib/compounding-worker.js +0 -21
  133. package/dist/lib/compounding-worker.js.map +0 -1
  134. package/dist/lib/compounding.d.ts +0 -20
  135. package/dist/lib/compounding.js +0 -45
  136. package/dist/lib/compounding.js.map +0 -1
  137. package/dist/lib/config.d.ts +0 -35
  138. package/dist/lib/config.js +0 -96
  139. package/dist/lib/config.js.map +0 -1
  140. package/dist/lib/context-format.d.ts +0 -7
  141. package/dist/lib/context-format.js +0 -21
  142. package/dist/lib/context-format.js.map +0 -1
  143. package/dist/lib/errors.d.ts +0 -18
  144. package/dist/lib/errors.js +0 -30
  145. package/dist/lib/errors.js.map +0 -1
  146. package/dist/lib/file-scanner.d.ts +0 -38
  147. package/dist/lib/file-scanner.js +0 -188
  148. package/dist/lib/file-scanner.js.map +0 -1
  149. package/dist/lib/graph-html.d.ts +0 -59
  150. package/dist/lib/graph-html.js +0 -859
  151. package/dist/lib/graph-html.js.map +0 -1
  152. package/dist/lib/installers.d.ts +0 -80
  153. package/dist/lib/installers.js +0 -602
  154. package/dist/lib/installers.js.map +0 -1
  155. package/dist/lib/integrations.d.ts +0 -23
  156. package/dist/lib/integrations.js +0 -25
  157. package/dist/lib/integrations.js.map +0 -1
  158. package/dist/lib/output.d.ts +0 -7
  159. package/dist/lib/output.js +0 -70
  160. package/dist/lib/output.js.map +0 -1
  161. package/dist/lib/platform-detect.d.ts +0 -23
  162. package/dist/lib/platform-detect.js +0 -359
  163. package/dist/lib/platform-detect.js.map +0 -1
  164. package/dist/lib/project-config.d.ts +0 -53
  165. package/dist/lib/project-config.js +0 -151
  166. package/dist/lib/project-config.js.map +0 -1
  167. package/dist/lib/prompt.d.ts +0 -15
  168. package/dist/lib/prompt.js +0 -213
  169. package/dist/lib/prompt.js.map +0 -1
  170. package/dist/lib/rate-limiter.d.ts +0 -13
  171. package/dist/lib/rate-limiter.js +0 -49
  172. package/dist/lib/rate-limiter.js.map +0 -1
  173. package/dist/lib/recall-filter.d.ts +0 -5
  174. package/dist/lib/recall-filter.js +0 -24
  175. package/dist/lib/recall-filter.js.map +0 -1
  176. package/dist/lib/session-store.d.ts +0 -15
  177. package/dist/lib/session-store.js +0 -62
  178. package/dist/lib/session-store.js.map +0 -1
  179. package/dist/lib/tui.d.ts +0 -57
  180. package/dist/lib/tui.js +0 -247
  181. package/dist/lib/tui.js.map +0 -1
  182. package/dist/lib/workspace-registry.d.ts +0 -47
  183. package/dist/lib/workspace-registry.js +0 -240
  184. package/dist/lib/workspace-registry.js.map +0 -1
  185. package/dist/mcp/channel.d.ts +0 -24
  186. package/dist/mcp/channel.js +0 -198
  187. package/dist/mcp/channel.js.map +0 -1
  188. package/dist/mcp/client.d.ts +0 -20
  189. package/dist/mcp/client.js +0 -131
  190. package/dist/mcp/client.js.map +0 -1
  191. package/dist/mcp/config.d.ts +0 -19
  192. package/dist/mcp/config.js +0 -48
  193. package/dist/mcp/config.js.map +0 -1
  194. package/dist/mcp/context-files.d.ts +0 -9
  195. package/dist/mcp/context-files.js +0 -90
  196. package/dist/mcp/context-files.js.map +0 -1
  197. package/dist/mcp/file-manifest.d.ts +0 -27
  198. package/dist/mcp/file-manifest.js +0 -68
  199. package/dist/mcp/file-manifest.js.map +0 -1
  200. package/dist/mcp/file-scanner.d.ts +0 -17
  201. package/dist/mcp/file-scanner.js +0 -77
  202. package/dist/mcp/file-scanner.js.map +0 -1
  203. package/dist/mcp/index.d.ts +0 -2
  204. package/dist/mcp/index.js +0 -51
  205. package/dist/mcp/index.js.map +0 -1
  206. package/dist/mcp/rate-limiter.d.ts +0 -14
  207. package/dist/mcp/rate-limiter.js +0 -60
  208. package/dist/mcp/rate-limiter.js.map +0 -1
  209. package/dist/mcp/server.d.ts +0 -6
  210. package/dist/mcp/server.js +0 -44
  211. package/dist/mcp/server.js.map +0 -1
  212. package/dist/mcp/session-store.d.ts +0 -16
  213. package/dist/mcp/session-store.js +0 -70
  214. package/dist/mcp/session-store.js.map +0 -1
  215. package/dist/mcp/tools/context.d.ts +0 -3
  216. package/dist/mcp/tools/context.js +0 -65
  217. package/dist/mcp/tools/context.js.map +0 -1
  218. package/dist/mcp/tools/insights.d.ts +0 -3
  219. package/dist/mcp/tools/insights.js +0 -24
  220. package/dist/mcp/tools/insights.js.map +0 -1
  221. package/dist/mcp/tools/integrations.d.ts +0 -3
  222. package/dist/mcp/tools/integrations.js +0 -27
  223. package/dist/mcp/tools/integrations.js.map +0 -1
  224. package/dist/mcp/tools/lists.d.ts +0 -3
  225. package/dist/mcp/tools/lists.js +0 -101
  226. package/dist/mcp/tools/lists.js.map +0 -1
  227. package/dist/mcp/tools/notes.d.ts +0 -3
  228. package/dist/mcp/tools/notes.js +0 -52
  229. package/dist/mcp/tools/notes.js.map +0 -1
  230. package/dist/mcp/tools/notifications.d.ts +0 -3
  231. package/dist/mcp/tools/notifications.js +0 -53
  232. package/dist/mcp/tools/notifications.js.map +0 -1
  233. package/dist/mcp/tools/records.d.ts +0 -3
  234. package/dist/mcp/tools/records.js +0 -74
  235. package/dist/mcp/tools/records.js.map +0 -1
  236. package/dist/mcp/tools/register.d.ts +0 -3
  237. package/dist/mcp/tools/register.js +0 -41
  238. package/dist/mcp/tools/register.js.map +0 -1
  239. package/dist/mcp/tools/relationships.d.ts +0 -3
  240. package/dist/mcp/tools/relationships.js +0 -47
  241. package/dist/mcp/tools/relationships.js.map +0 -1
  242. package/dist/mcp/tools/scan.d.ts +0 -3
  243. package/dist/mcp/tools/scan.js +0 -37
  244. package/dist/mcp/tools/scan.js.map +0 -1
  245. package/dist/mcp/tools/schema.d.ts +0 -3
  246. package/dist/mcp/tools/schema.js +0 -108
  247. package/dist/mcp/tools/schema.js.map +0 -1
  248. package/dist/mcp/tools/search.d.ts +0 -3
  249. package/dist/mcp/tools/search.js +0 -8
  250. package/dist/mcp/tools/search.js.map +0 -1
  251. package/dist/mcp/tools/tasks.d.ts +0 -3
  252. package/dist/mcp/tools/tasks.js +0 -88
  253. package/dist/mcp/tools/tasks.js.map +0 -1
  254. package/dist/mcp/workspace-data-dir.d.ts +0 -2
  255. package/dist/mcp/workspace-data-dir.js +0 -28
  256. package/dist/mcp/workspace-data-dir.js.map +0 -1
  257. package/dist/orchestration/budget.d.ts +0 -32
  258. package/dist/orchestration/budget.js +0 -72
  259. package/dist/orchestration/budget.js.map +0 -1
  260. package/dist/orchestration/executor.d.ts +0 -59
  261. package/dist/orchestration/executor.js +0 -197
  262. package/dist/orchestration/executor.js.map +0 -1
  263. package/dist/orchestration/router.d.ts +0 -30
  264. package/dist/orchestration/router.js +0 -98
  265. package/dist/orchestration/router.js.map +0 -1
  266. package/dist/orchestration/templates.d.ts +0 -11
  267. package/dist/orchestration/templates.js +0 -99
  268. package/dist/orchestration/templates.js.map +0 -1
  269. package/dist/orchestration/types.d.ts +0 -58
  270. package/dist/orchestration/types.js +0 -7
  271. package/dist/orchestration/types.js.map +0 -1
  272. package/dist/plugin/auto-capture.d.ts +0 -11
  273. package/dist/plugin/auto-capture.js +0 -135
  274. package/dist/plugin/auto-capture.js.map +0 -1
  275. package/dist/plugin/auto-recall-worker.d.ts +0 -2
  276. package/dist/plugin/auto-recall-worker.js +0 -74
  277. package/dist/plugin/auto-recall-worker.js.map +0 -1
  278. package/dist/plugin/auto-recall.d.ts +0 -11
  279. package/dist/plugin/auto-recall.js +0 -186
  280. package/dist/plugin/auto-recall.js.map +0 -1
  281. package/dist/plugin/auto-register.d.ts +0 -10
  282. package/dist/plugin/auto-register.js +0 -81
  283. package/dist/plugin/auto-register.js.map +0 -1
  284. package/dist/plugin/auto-scan.d.ts +0 -10
  285. package/dist/plugin/auto-scan.js +0 -54
  286. package/dist/plugin/auto-scan.js.map +0 -1
  287. package/dist/plugin/auto-session-start.d.ts +0 -14
  288. package/dist/plugin/auto-session-start.js +0 -156
  289. package/dist/plugin/auto-session-start.js.map +0 -1
  290. package/dist/plugin/capture-filter.d.ts +0 -21
  291. package/dist/plugin/capture-filter.js +0 -32
  292. package/dist/plugin/capture-filter.js.map +0 -1
  293. package/dist/plugin/config.d.ts +0 -61
  294. package/dist/plugin/config.js +0 -182
  295. package/dist/plugin/config.js.map +0 -1
  296. package/dist/plugin/context-files.d.ts +0 -23
  297. package/dist/plugin/context-files.js +0 -103
  298. package/dist/plugin/context-files.js.map +0 -1
  299. package/dist/plugin/context-format.d.ts +0 -18
  300. package/dist/plugin/context-format.js +0 -34
  301. package/dist/plugin/context-format.js.map +0 -1
  302. package/dist/plugin/file-manifest.d.ts +0 -27
  303. package/dist/plugin/file-manifest.js +0 -68
  304. package/dist/plugin/file-manifest.js.map +0 -1
  305. package/dist/plugin/file-scanner.d.ts +0 -19
  306. package/dist/plugin/file-scanner.js +0 -90
  307. package/dist/plugin/file-scanner.js.map +0 -1
  308. package/dist/plugin/nex-client.d.ts +0 -50
  309. package/dist/plugin/nex-client.js +0 -129
  310. package/dist/plugin/nex-client.js.map +0 -1
  311. package/dist/plugin/rate-limiter.d.ts +0 -26
  312. package/dist/plugin/rate-limiter.js +0 -65
  313. package/dist/plugin/rate-limiter.js.map +0 -1
  314. package/dist/plugin/recall-cache.d.ts +0 -41
  315. package/dist/plugin/recall-cache.js +0 -195
  316. package/dist/plugin/recall-cache.js.map +0 -1
  317. package/dist/plugin/recall-filter.d.ts +0 -13
  318. package/dist/plugin/recall-filter.js +0 -39
  319. package/dist/plugin/recall-filter.js.map +0 -1
  320. package/dist/plugin/session-store.d.ts +0 -23
  321. package/dist/plugin/session-store.js +0 -73
  322. package/dist/plugin/session-store.js.map +0 -1
  323. package/dist/plugin/workspace-data-dir.d.ts +0 -2
  324. package/dist/plugin/workspace-data-dir.js +0 -31
  325. package/dist/plugin/workspace-data-dir.js.map +0 -1
  326. package/dist/tui/agent-colors.d.ts +0 -19
  327. package/dist/tui/agent-colors.js +0 -34
  328. package/dist/tui/agent-colors.js.map +0 -1
  329. package/dist/tui/app.d.ts +0 -14
  330. package/dist/tui/app.js +0 -181
  331. package/dist/tui/app.js.map +0 -1
  332. package/dist/tui/channel-colors.d.ts +0 -16
  333. package/dist/tui/channel-colors.js +0 -43
  334. package/dist/tui/channel-colors.js.map +0 -1
  335. package/dist/tui/components/agent-card.d.ts +0 -11
  336. package/dist/tui/components/agent-card.js +0 -40
  337. package/dist/tui/components/agent-card.js.map +0 -1
  338. package/dist/tui/components/banner.d.ts +0 -44
  339. package/dist/tui/components/banner.js +0 -130
  340. package/dist/tui/components/banner.js.map +0 -1
  341. package/dist/tui/components/channel-colors.d.ts +0 -21
  342. package/dist/tui/components/channel-colors.js +0 -53
  343. package/dist/tui/components/channel-colors.js.map +0 -1
  344. package/dist/tui/components/channel-message.d.ts +0 -53
  345. package/dist/tui/components/channel-message.js +0 -66
  346. package/dist/tui/components/channel-message.js.map +0 -1
  347. package/dist/tui/components/chat-input.d.ts +0 -11
  348. package/dist/tui/components/chat-input.js +0 -19
  349. package/dist/tui/components/chat-input.js.map +0 -1
  350. package/dist/tui/components/data-table.d.ts +0 -11
  351. package/dist/tui/components/data-table.js +0 -47
  352. package/dist/tui/components/data-table.js.map +0 -1
  353. package/dist/tui/components/error-box.d.ts +0 -11
  354. package/dist/tui/components/error-box.js +0 -59
  355. package/dist/tui/components/error-box.js.map +0 -1
  356. package/dist/tui/components/help-screen.d.ts +0 -3
  357. package/dist/tui/components/help-screen.js +0 -63
  358. package/dist/tui/components/help-screen.js.map +0 -1
  359. package/dist/tui/components/index.d.ts +0 -17
  360. package/dist/tui/components/index.js +0 -10
  361. package/dist/tui/components/index.js.map +0 -1
  362. package/dist/tui/components/inline-confirm.d.ts +0 -14
  363. package/dist/tui/components/inline-confirm.js +0 -13
  364. package/dist/tui/components/inline-confirm.js.map +0 -1
  365. package/dist/tui/components/inline-select.d.ts +0 -21
  366. package/dist/tui/components/inline-select.js +0 -20
  367. package/dist/tui/components/inline-select.js.map +0 -1
  368. package/dist/tui/components/markdown.d.ts +0 -6
  369. package/dist/tui/components/markdown.js +0 -179
  370. package/dist/tui/components/markdown.js.map +0 -1
  371. package/dist/tui/components/mention-autocomplete.d.ts +0 -79
  372. package/dist/tui/components/mention-autocomplete.js +0 -250
  373. package/dist/tui/components/mention-autocomplete.js.map +0 -1
  374. package/dist/tui/components/message-list.d.ts +0 -18
  375. package/dist/tui/components/message-list.js +0 -29
  376. package/dist/tui/components/message-list.js.map +0 -1
  377. package/dist/tui/components/picker.d.ts +0 -16
  378. package/dist/tui/components/picker.js +0 -32
  379. package/dist/tui/components/picker.js.map +0 -1
  380. package/dist/tui/components/progress-steps.d.ts +0 -13
  381. package/dist/tui/components/progress-steps.js +0 -21
  382. package/dist/tui/components/progress-steps.js.map +0 -1
  383. package/dist/tui/components/slack/compose.d.ts +0 -27
  384. package/dist/tui/components/slack/compose.js +0 -147
  385. package/dist/tui/components/slack/compose.js.map +0 -1
  386. package/dist/tui/components/slack/layout.d.ts +0 -36
  387. package/dist/tui/components/slack/layout.js +0 -96
  388. package/dist/tui/components/slack/layout.js.map +0 -1
  389. package/dist/tui/components/slack/messages.d.ts +0 -72
  390. package/dist/tui/components/slack/messages.js +0 -177
  391. package/dist/tui/components/slack/messages.js.map +0 -1
  392. package/dist/tui/components/slack/quick-switcher.d.ts +0 -33
  393. package/dist/tui/components/slack/quick-switcher.js +0 -98
  394. package/dist/tui/components/slack/quick-switcher.js.map +0 -1
  395. package/dist/tui/components/slack/sidebar-types.d.ts +0 -65
  396. package/dist/tui/components/slack/sidebar-types.js +0 -7
  397. package/dist/tui/components/slack/sidebar-types.js.map +0 -1
  398. package/dist/tui/components/slack/sidebar.d.ts +0 -46
  399. package/dist/tui/components/slack/sidebar.js +0 -52
  400. package/dist/tui/components/slack/sidebar.js.map +0 -1
  401. package/dist/tui/components/slack/thread-panel.d.ts +0 -45
  402. package/dist/tui/components/slack/thread-panel.js +0 -47
  403. package/dist/tui/components/slack/thread-panel.js.map +0 -1
  404. package/dist/tui/components/slash-autocomplete.d.ts +0 -83
  405. package/dist/tui/components/slash-autocomplete.js +0 -233
  406. package/dist/tui/components/slash-autocomplete.js.map +0 -1
  407. package/dist/tui/components/spinner.d.ts +0 -17
  408. package/dist/tui/components/spinner.js +0 -30
  409. package/dist/tui/components/spinner.js.map +0 -1
  410. package/dist/tui/components/status-bar.d.ts +0 -23
  411. package/dist/tui/components/status-bar.js +0 -55
  412. package/dist/tui/components/status-bar.js.map +0 -1
  413. package/dist/tui/components/success-box.d.ts +0 -7
  414. package/dist/tui/components/success-box.js +0 -10
  415. package/dist/tui/components/success-box.js.map +0 -1
  416. package/dist/tui/components/tool-indicator.d.ts +0 -12
  417. package/dist/tui/components/tool-indicator.js +0 -18
  418. package/dist/tui/components/tool-indicator.js.map +0 -1
  419. package/dist/tui/components/viewport.d.ts +0 -9
  420. package/dist/tui/components/viewport.js +0 -24
  421. package/dist/tui/components/viewport.js.map +0 -1
  422. package/dist/tui/generative/bindings.d.ts +0 -27
  423. package/dist/tui/generative/bindings.js +0 -152
  424. package/dist/tui/generative/bindings.js.map +0 -1
  425. package/dist/tui/generative/registry.d.ts +0 -19
  426. package/dist/tui/generative/registry.js +0 -31
  427. package/dist/tui/generative/registry.js.map +0 -1
  428. package/dist/tui/generative/renderer.d.ts +0 -24
  429. package/dist/tui/generative/renderer.js +0 -160
  430. package/dist/tui/generative/renderer.js.map +0 -1
  431. package/dist/tui/generative/types.d.ts +0 -68
  432. package/dist/tui/generative/types.js +0 -7
  433. package/dist/tui/generative/types.js.map +0 -1
  434. package/dist/tui/hooks/use-cancellable.d.ts +0 -28
  435. package/dist/tui/hooks/use-cancellable.js +0 -51
  436. package/dist/tui/hooks/use-cancellable.js.map +0 -1
  437. package/dist/tui/hooks/use-streaming.d.ts +0 -44
  438. package/dist/tui/hooks/use-streaming.js +0 -105
  439. package/dist/tui/hooks/use-streaming.js.map +0 -1
  440. package/dist/tui/index.d.ts +0 -4
  441. package/dist/tui/index.js +0 -7
  442. package/dist/tui/index.js.map +0 -1
  443. package/dist/tui/keybindings.d.ts +0 -25
  444. package/dist/tui/keybindings.js +0 -277
  445. package/dist/tui/keybindings.js.map +0 -1
  446. package/dist/tui/register-views.d.ts +0 -8
  447. package/dist/tui/register-views.js +0 -122
  448. package/dist/tui/register-views.js.map +0 -1
  449. package/dist/tui/router.d.ts +0 -29
  450. package/dist/tui/router.js +0 -87
  451. package/dist/tui/router.js.map +0 -1
  452. package/dist/tui/services/agent-service.d.ts +0 -58
  453. package/dist/tui/services/agent-service.js +0 -197
  454. package/dist/tui/services/agent-service.js.map +0 -1
  455. package/dist/tui/services/calendar-service.d.ts +0 -31
  456. package/dist/tui/services/calendar-service.js +0 -133
  457. package/dist/tui/services/calendar-service.js.map +0 -1
  458. package/dist/tui/services/chat-service.d.ts +0 -28
  459. package/dist/tui/services/chat-service.js +0 -91
  460. package/dist/tui/services/chat-service.js.map +0 -1
  461. package/dist/tui/services/orchestration-service.d.ts +0 -42
  462. package/dist/tui/services/orchestration-service.js +0 -153
  463. package/dist/tui/services/orchestration-service.js.map +0 -1
  464. package/dist/tui/slash-commands.d.ts +0 -106
  465. package/dist/tui/slash-commands.js +0 -1421
  466. package/dist/tui/slash-commands.js.map +0 -1
  467. package/dist/tui/store.d.ts +0 -96
  468. package/dist/tui/store.js +0 -120
  469. package/dist/tui/store.js.map +0 -1
  470. package/dist/tui/theme.d.ts +0 -40
  471. package/dist/tui/theme.js +0 -39
  472. package/dist/tui/theme.js.map +0 -1
  473. package/dist/tui/tui-context.d.ts +0 -22
  474. package/dist/tui/tui-context.js +0 -17
  475. package/dist/tui/tui-context.js.map +0 -1
  476. package/dist/tui/views/agent-list.d.ts +0 -8
  477. package/dist/tui/views/agent-list.js +0 -11
  478. package/dist/tui/views/agent-list.js.map +0 -1
  479. package/dist/tui/views/ask-chat.d.ts +0 -9
  480. package/dist/tui/views/ask-chat.js +0 -40
  481. package/dist/tui/views/ask-chat.js.map +0 -1
  482. package/dist/tui/views/calendar.d.ts +0 -15
  483. package/dist/tui/views/calendar.js +0 -29
  484. package/dist/tui/views/calendar.js.map +0 -1
  485. package/dist/tui/views/chat.d.ts +0 -18
  486. package/dist/tui/views/chat.js +0 -28
  487. package/dist/tui/views/chat.js.map +0 -1
  488. package/dist/tui/views/generative.d.ts +0 -14
  489. package/dist/tui/views/generative.js +0 -37
  490. package/dist/tui/views/generative.js.map +0 -1
  491. package/dist/tui/views/help.d.ts +0 -6
  492. package/dist/tui/views/help.js +0 -9
  493. package/dist/tui/views/help.js.map +0 -1
  494. package/dist/tui/views/home-screen.d.ts +0 -67
  495. package/dist/tui/views/home-screen.js +0 -192
  496. package/dist/tui/views/home-screen.js.map +0 -1
  497. package/dist/tui/views/home.d.ts +0 -33
  498. package/dist/tui/views/home.js +0 -60
  499. package/dist/tui/views/home.js.map +0 -1
  500. package/dist/tui/views/index.d.ts +0 -20
  501. package/dist/tui/views/index.js +0 -11
  502. package/dist/tui/views/index.js.map +0 -1
  503. package/dist/tui/views/insights.d.ts +0 -19
  504. package/dist/tui/views/insights.js +0 -46
  505. package/dist/tui/views/insights.js.map +0 -1
  506. package/dist/tui/views/orchestration.d.ts +0 -18
  507. package/dist/tui/views/orchestration.js +0 -73
  508. package/dist/tui/views/orchestration.js.map +0 -1
  509. package/dist/tui/views/record-detail.d.ts +0 -10
  510. package/dist/tui/views/record-detail.js +0 -22
  511. package/dist/tui/views/record-detail.js.map +0 -1
  512. package/dist/tui/views/record-list.d.ts +0 -15
  513. package/dist/tui/views/record-list.js +0 -22
  514. package/dist/tui/views/record-list.js.map +0 -1
  515. package/dist/tui/views/slack-channel-header.d.ts +0 -15
  516. package/dist/tui/views/slack-channel-header.js +0 -16
  517. package/dist/tui/views/slack-channel-header.js.map +0 -1
  518. package/dist/tui/views/slack-home.d.ts +0 -21
  519. package/dist/tui/views/slack-home.js +0 -572
  520. package/dist/tui/views/slack-home.js.map +0 -1
  521. package/dist/tui/views/stream.d.ts +0 -16
  522. package/dist/tui/views/stream.js +0 -210
  523. package/dist/tui/views/stream.js.map +0 -1
  524. package/dist/tui/views/task-board.d.ts +0 -21
  525. package/dist/tui/views/task-board.js +0 -33
  526. package/dist/tui/views/task-board.js.map +0 -1
  527. package/dist/tui/views/timeline.d.ts +0 -17
  528. package/dist/tui/views/timeline.js +0 -24
  529. package/dist/tui/views/timeline.js.map +0 -1
@@ -1,859 +0,0 @@
1
- /**
2
- * Self-contained HTML graph visualization using D3.js with SVG rendering.
3
- * Exact clone of Zep's graph approach, adapted for Nex entity/insight structure.
4
- * Generates a single HTML string that can be opened in any browser.
5
- */
6
- const NODE_COLORS = {
7
- person: "#EC4899", // pink-500
8
- company: "#3B82F6", // blue-500
9
- deal: "#F59E0B", // amber-500
10
- lead: "#EF4444", // red-500
11
- contact: "#06B6D4", // cyan-500
12
- opportunity: "#F97316", // orange-500
13
- task: "#10B981", // emerald-500
14
- note: "#84CC16", // lime-500
15
- event: "#8B5CF6", // violet-500
16
- topic: "#14B8A6", // teal-500
17
- product: "#A855F7", // purple-500
18
- project: "#6366F1", // indigo-500
19
- ghost: "#8B5CF6", // violet-500
20
- entity_insight: "#EC4899", // pink-500
21
- knowledge_insight: "#06B6D4", // cyan-500
22
- };
23
- const DEFAULT_COLOR = "#EC4899";
24
- function escapeHtml(str) {
25
- return str
26
- .replace(/&/g, "&")
27
- .replace(/</g, "&lt;")
28
- .replace(/>/g, "&gt;")
29
- .replace(/"/g, "&quot;")
30
- .replace(/'/g, "&#39;");
31
- }
32
- function escapeJsonForHtml(data) {
33
- return JSON.stringify(data)
34
- .replace(/</g, "\\u003c")
35
- .replace(/>/g, "\\u003e")
36
- .replace(/&/g, "\\u0026");
37
- }
38
- export function generateGraphHtml(data) {
39
- const nodeColors = { ...NODE_COLORS };
40
- const typeSet = new Set();
41
- for (const n of data.nodes)
42
- typeSet.add(n.type);
43
- for (const n of (data.insight_nodes ?? []))
44
- typeSet.add(n.source);
45
- const legendTypes = Array.from(typeSet).sort();
46
- // Count total insights
47
- let totalInsights = 0;
48
- for (const key of Object.keys(data.insights ?? {})) {
49
- totalInsights += (data.insights[key] ?? []).length;
50
- }
51
- totalInsights += (data.insight_nodes ?? []).length;
52
- const totalConnections = data.total_edges + data.total_context_edges;
53
- return `<!DOCTYPE html>
54
- <html lang="en">
55
- <head>
56
- <meta charset="utf-8">
57
- <meta name="viewport" content="width=device-width,initial-scale=1">
58
- <title>Nex — Workspace Graph</title>
59
- <style>
60
- *{margin:0;padding:0;box-sizing:border-box}
61
- body{background:#0f172a;color:#e2e8f0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;overflow:hidden}
62
- svg{width:100%;height:100vh;cursor:grab;border-radius:0;position:fixed;top:0;left:0;z-index:1}
63
- svg:active{cursor:grabbing}
64
- #search-box{position:fixed;top:16px;left:16px;z-index:10;background:rgba(30,41,59,0.9);border:1px solid #334155;border-radius:10px;padding:8px 14px;color:#e2e8f0;font-size:14px;width:240px;outline:none;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
65
- #search-box::placeholder{color:#64748b}
66
- #search-box:focus{border-color:#EC4899;box-shadow:0 0 0 2px rgba(236,72,153,.2)}
67
- #stats{position:fixed;top:16px;right:16px;z-index:10;background:rgba(30,41,59,0.9);border:1px solid #334155;border-radius:10px;padding:8px 14px;font-size:13px;color:#94a3b8;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
68
- #legend{position:fixed;bottom:16px;left:16px;z-index:10;background:rgba(30,41,59,0.9);border:1px solid #334155;border-radius:10px;padding:10px 14px;font-size:13px;max-height:50vh;overflow-y:auto;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
69
- .legend-item{display:flex;align-items:center;gap:8px;margin:4px 0;color:#94a3b8}
70
- .legend-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
71
- .legend-line{width:20px;height:2px;flex-shrink:0;border-radius:1px}
72
- .legend-sep{border-top:1px solid #334155;margin:6px 0}
73
- #detail-panel{position:fixed;top:0;right:-380px;width:380px;height:100vh;background:rgba(30,41,59,0.95);border-left:1px solid #334155;z-index:20;padding:20px;overflow-y:auto;transition:right .25s cubic-bezier(.4,0,.2,1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
74
- #detail-panel.open{right:0}
75
- #detail-panel h3{margin-bottom:12px;font-size:16px;color:#f1f5f9;font-weight:600}
76
- #detail-panel .field{margin-bottom:10px;font-size:13px}
77
- #detail-panel .field .label{color:#64748b;font-size:11px;text-transform:uppercase;letter-spacing:.5px;font-weight:500}
78
- #detail-panel .field .value{color:#cbd5e1;margin-top:2px;word-wrap:break-word;overflow-wrap:break-word;white-space:pre-wrap}
79
- .insight-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:10px 12px;margin-top:6px}
80
- .insight-card .insight-type{display:inline-block;background:#334155;border-radius:4px;padding:2px 8px;font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:#94a3b8;margin-right:6px;font-weight:500}
81
- .insight-card .insight-confidence{font-size:11px;color:#64748b;float:right}
82
- .insight-card .insight-content{margin-top:6px;font-size:12px;color:#94a3b8;line-height:1.5;word-wrap:break-word;overflow-wrap:break-word;white-space:pre-wrap}
83
- #detail-close{position:absolute;top:12px;right:12px;background:none;border:none;color:#64748b;cursor:pointer;font-size:18px;transition:color .15s}
84
- #detail-close:hover{color:#e2e8f0}
85
- </style>
86
- </head>
87
- <body>
88
- <input id="search-box" type="text" placeholder="Search entities..." autocomplete="off">
89
- <div id="stats">${escapeHtml(String(data.total_nodes))} entities &middot; ${escapeHtml(String(totalConnections))} connections &middot; ${escapeHtml(String(totalInsights))} insights</div>
90
- <div id="legend">
91
- ${legendTypes
92
- .map((t) => `<div class="legend-item"><span class="legend-dot" style="background:${escapeHtml(nodeColors[t] ?? DEFAULT_COLOR)}"></span>${escapeHtml(t)}</div>`)
93
- .join("\n")}
94
- <div class="legend-sep"></div>
95
- <div class="legend-item"><span class="legend-line" style="background:#475569"></span>Formal</div>
96
- <div class="legend-item"><span class="legend-line" style="background:#8B5CF6"></span>Context</div>
97
- <div class="legend-item"><span class="legend-line" style="background:#F59E0B"></span>Triplet</div>
98
- <div class="legend-item"><span class="legend-line" style="background:#EC4899"></span>Insight</div>
99
- </div>
100
- <div id="detail-panel">
101
- <button id="detail-close">&times;</button>
102
- <h3 id="detail-name"></h3>
103
- <div id="detail-body"></div>
104
- </div>
105
-
106
- <!-- D3.js v7 — same as Zep's force-graph approach -->
107
- <script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
108
-
109
- <script id="graph-data" type="application/json">${escapeJsonForHtml(data)}</script>
110
-
111
- <script>
112
- (function(){
113
- var data = JSON.parse(document.getElementById("graph-data").textContent);
114
- var width = window.innerWidth;
115
- var height = window.innerHeight;
116
-
117
- var nodeColors = {
118
- person:"#EC4899", company:"#3B82F6", deal:"#F59E0B",
119
- lead:"#EF4444", contact:"#06B6D4", opportunity:"#F97316",
120
- task:"#10B981", note:"#84CC16", event:"#8B5CF6",
121
- topic:"#14B8A6", product:"#A855F7", project:"#6366F1",
122
- ghost:"#8B5CF6", entity_insight:"#EC4899", knowledge_insight:"#06B6D4"
123
- };
124
- var defaultColor = "#EC4899";
125
- var edgeTypeColors = {formal:"#475569", context:"#8B5CF6", triplet:"#F59E0B", insight:"#EC4899"};
126
-
127
- // ── Build entity ID set (entities + ghosts, NO insights yet) ──
128
- var entityIdSet = {};
129
- data.nodes.forEach(function(n){ entityIdSet[n.id] = true; });
130
-
131
- // ── Index insight nodes by target entity for on-demand expansion ──
132
- var insightsByEntity = {};
133
- (data.context_edges || []).forEach(function(e){
134
- if (e.edge_type === "insight") {
135
- var targetId = entityIdSet[e.target] ? e.target : (entityIdSet[e.source] ? e.source : null);
136
- var insightId = e.target === targetId ? e.source : e.target;
137
- if (targetId) {
138
- if (!insightsByEntity[targetId]) insightsByEntity[targetId] = [];
139
- var insData = null;
140
- (data.insight_nodes || []).forEach(function(ins){ if (ins.id === insightId) insData = ins; });
141
- if (insData) insightsByEntity[targetId].push({node: insData, edge: e});
142
- }
143
- }
144
- });
145
-
146
- // ── Count insights per entity ──
147
- var insightCount = {};
148
- // Use insightsByEntity as authoritative count (same data as insightsMap, avoid double-counting)
149
- for (var eid in insightsByEntity) insightCount[eid] = insightsByEntity[eid].length;
150
- var insightsMap = data.insights || {};
151
- // Only count from insightsMap for entities NOT already counted via insightsByEntity
152
- for (var eid2 in insightsMap) {
153
- if (!insightCount[eid2]) insightCount[eid2] = (insightsMap[eid2] || []).length;
154
- }
155
-
156
- // ── Build links from formal edges + non-insight context edges ──
157
- // Group links by source-target pair for curve offset (like Zep)
158
- var linkGroupMap = {};
159
- function addLink(source, target, label, edgeType) {
160
- if (!entityIdSet[source] || !entityIdSet[target]) return;
161
- var key = source < target ? source + "-" + target : target + "-" + source;
162
- if (!linkGroupMap[key]) linkGroupMap[key] = [];
163
- linkGroupMap[key].push({source: source, target: target, label: label, edgeType: edgeType, color: edgeTypeColors[edgeType] || "#475569"});
164
- }
165
- (data.edges || []).forEach(function(e){ addLink(e.source, e.target, e.label, "formal"); });
166
- (data.context_edges || []).forEach(function(e){
167
- if (e.edge_type === "insight") return;
168
- addLink(e.source, e.target, e.label, e.edge_type);
169
- });
170
-
171
- // Assign curve strengths per group (Zep's pattern)
172
- var baseLinks = [];
173
- for (var gk in linkGroupMap) {
174
- var group = linkGroupMap[gk];
175
- var count = group.length;
176
- var baseStrength = 0.2;
177
- group.forEach(function(lnk, idx){
178
- lnk.curveStrength = count > 1 ? (-baseStrength + idx * (baseStrength * 2) / (count - 1)) : 0;
179
- baseLinks.push(lnk);
180
- });
181
- }
182
-
183
- // ── Build degree map ──
184
- var degree = {};
185
- data.nodes.forEach(function(n){ degree[n.id] = 0; });
186
- baseLinks.forEach(function(l){
187
- degree[l.source] = (degree[l.source] || 0) + 1;
188
- degree[l.target] = (degree[l.target] || 0) + 1;
189
- });
190
-
191
- // ── Identify isolated & ghost nodes ──
192
- var linkedNodeIds = {};
193
- baseLinks.forEach(function(l){ linkedNodeIds[l.source] = true; linkedNodeIds[l.target] = true; });
194
- var isolatedNodeIds = {};
195
- data.nodes.forEach(function(n){ if (!linkedNodeIds[n.id]) isolatedNodeIds[n.id] = true; });
196
-
197
- // ── Build D3 node objects ──
198
- var entityNodes = data.nodes.map(function(n){
199
- return {
200
- id: n.id, name: n.name, type: n.type, nodeKind: "entity",
201
- primary_attribute: n.primary_attribute || "", created_at: n.created_at || "",
202
- summary: n.summary || "",
203
- color: nodeColors[n.type] || defaultColor,
204
- insightCount: insightCount[n.id] || 0
205
- };
206
- });
207
-
208
- // ── Track expanded insights ──
209
- var expandedEntities = {};
210
-
211
- // ── Current working nodes/links arrays ──
212
- var currentNodes = entityNodes.slice();
213
- var currentLinks = baseLinks.map(function(l){ return {source: l.source, target: l.target, label: l.label, edgeType: l.edgeType, color: l.color, curveStrength: l.curveStrength}; });
214
-
215
- function rebuildGraphArrays() {
216
- currentNodes = entityNodes.slice();
217
- currentLinks = baseLinks.map(function(l){ return {source: l.source, target: l.target, label: l.label, edgeType: l.edgeType, color: l.color, curveStrength: l.curveStrength}; });
218
- for (var entId in expandedEntities) {
219
- var items = insightsByEntity[entId] || [];
220
- var entNode = null;
221
- entityNodes.forEach(function(n){ if (n.id === entId) entNode = n; });
222
- items.forEach(function(item, i){
223
- var ins = item.node;
224
- var fullContent = ins.content || "";
225
- var label = fullContent.length > 50 ? fullContent.substring(0, 48) + ".." : fullContent;
226
- var angle = (2 * Math.PI * i) / items.length;
227
- var dist = 60;
228
- currentNodes.push({
229
- id: ins.id, name: label, fullContent: fullContent,
230
- type: ins.source, nodeKind: "insight",
231
- primary_attribute: ins.type, created_at: "",
232
- color: nodeColors[ins.source] || "#EC4899",
233
- insightCount: 0, confidence: ins.confidence,
234
- x: entNode ? entNode.x + Math.cos(angle) * dist : width/2,
235
- y: entNode ? entNode.y + Math.sin(angle) * dist : height/2
236
- });
237
- currentLinks.push({
238
- source: ins.id, target: entId, label: ins.type,
239
- edgeType: "insight", color: "#EC4899", curveStrength: 0
240
- });
241
- });
242
- }
243
- }
244
-
245
- // ── Focus/search/hover state ──
246
- var focusedNodeId = null;
247
- var focusedSet = {};
248
- var searchActive = false;
249
- var searchMatches = {};
250
-
251
- // ══════════════════════════════════════════════════════════
252
- // SVG SETUP — exact Zep pattern: <svg> → <g> for zoom
253
- // ══════════════════════════════════════════════════════════
254
- var svg = d3.select("body").append("svg")
255
- .attr("width", width)
256
- .attr("height", height)
257
- .attr("viewBox", "0 0 " + width + " " + height)
258
- .style("background-color", "#0f172a");
259
-
260
- // Drop-shadow filter (Zep: drop-shadow(0 2px 4px rgba(0,0,0,0.2)))
261
- var defs = svg.append("defs");
262
- var filter = defs.append("filter").attr("id", "drop-shadow").attr("x", "-50%").attr("y", "-50%").attr("width", "200%").attr("height", "200%");
263
- filter.append("feDropShadow").attr("dx", 0).attr("dy", 2).attr("stdDeviation", 2).attr("flood-color", "rgba(0,0,0,0.3)");
264
-
265
- var g = svg.append("g");
266
-
267
- // ── Zoom behavior — Zep: scaleExtent [0.1, 4] ──
268
- var currentZoomScale = 0.8;
269
- var LABEL_ZOOM_THRESHOLD = 0.6; // node labels appear above this
270
- var LINK_LABEL_ZOOM_THRESHOLD = 0.9; // link labels appear above this
271
-
272
- var zoomBehavior = d3.zoom()
273
- .scaleExtent([0.1, 4])
274
- .on("zoom", function(event){
275
- g.attr("transform", event.transform);
276
- var newScale = event.transform.k;
277
- // Toggle label visibility on scale change
278
- if ((newScale >= LABEL_ZOOM_THRESHOLD) !== (currentZoomScale >= LABEL_ZOOM_THRESHOLD)) {
279
- nodeLayer.selectAll("g.node-group > text:not(.insight-badge)")
280
- .attr("display", newScale >= LABEL_ZOOM_THRESHOLD ? null : "none");
281
- }
282
- if ((newScale >= LINK_LABEL_ZOOM_THRESHOLD) !== (currentZoomScale >= LINK_LABEL_ZOOM_THRESHOLD)) {
283
- linkLayer.selectAll(".link-label")
284
- .attr("display", newScale >= LINK_LABEL_ZOOM_THRESHOLD ? null : "none");
285
- }
286
- currentZoomScale = newScale;
287
- });
288
- svg.call(zoomBehavior).call(zoomBehavior.transform, d3.zoomIdentity.scale(0.8).translate(width * 0.1, height * 0.1));
289
-
290
- // Click on SVG background → unfocus
291
- svg.on("click", function(event){
292
- if (event.target.tagName === "svg" || event.target === svg.node()) {
293
- unfocus();
294
- }
295
- });
296
-
297
- // ── Layer groups (links below nodes) ──
298
- var linkLayer = g.append("g").attr("class", "links");
299
- var nodeLayer = g.append("g").attr("class", "nodes");
300
-
301
- // ══════════════════════════════════════════════════════════
302
- // D3 FORCE SIMULATION — exact Zep parameters
303
- // ══════════════════════════════════════════════════════════
304
- var simulation = d3.forceSimulation(currentNodes)
305
- .force("link", d3.forceLink(currentLinks).id(function(d){ return d.id; }).distance(200).strength(0.2))
306
- .force("charge", d3.forceManyBody()
307
- .strength(function(d){ return isolatedNodeIds[d.id] ? -500 : -3000; })
308
- .distanceMin(20).distanceMax(500).theta(0.8))
309
- .force("center", d3.forceCenter(width / 2, height / 2).strength(0.05))
310
- .force("collide", d3.forceCollide().radius(50).strength(0.3).iterations(5))
311
- .force("isolatedGravity", d3.forceRadial(100, width / 2, height / 2)
312
- .strength(function(d){ return isolatedNodeIds[d.id] ? 0.15 : (d.type === "ghost" ? 0.03 : 0.01); }))
313
- .velocityDecay(0.4)
314
- .alphaDecay(0.05)
315
- .alphaMin(0.001);
316
-
317
- // ══════════════════════════════════════════════════════════
318
- // RENDER FUNCTIONS
319
- // ══════════════════════════════════════════════════════════
320
- var linkSelection, nodeSelection;
321
-
322
- function render() {
323
- // ── LINKS ──
324
- linkLayer.selectAll("g.link-group").remove();
325
- linkSelection = linkLayer.selectAll("g.link-group")
326
- .data(currentLinks, function(d){ return d.source.id + "-" + d.target.id + "-" + d.label; })
327
- .join("g")
328
- .attr("class", "link-group");
329
-
330
- // Path for each link
331
- linkSelection.append("path")
332
- .attr("stroke", function(d){ return d.color; })
333
- .attr("stroke-opacity", 0.6)
334
- .attr("stroke-width", 1)
335
- .attr("fill", "none")
336
- .attr("cursor", "pointer");
337
-
338
- // Label group (rect + text) — Zep pattern
339
- var labelG = linkSelection.append("g")
340
- .attr("class", "link-label")
341
- .attr("cursor", "pointer")
342
- .attr("display", currentZoomScale >= LINK_LABEL_ZOOM_THRESHOLD ? null : "none");
343
-
344
- labelG.append("rect")
345
- .attr("fill", "#1e293b")
346
- .attr("rx", 4).attr("ry", 4)
347
- .attr("opacity", 0.9);
348
-
349
- labelG.append("text")
350
- .attr("fill", "#94a3b8")
351
- .attr("font-size", "8px")
352
- .attr("text-anchor", "middle")
353
- .attr("dominant-baseline", "middle")
354
- .attr("pointer-events", "none")
355
- .text(function(d){ return d.label || ""; });
356
-
357
- // ── NODES ──
358
- nodeLayer.selectAll("g.node-group").remove();
359
- nodeSelection = nodeLayer.selectAll("g.node-group")
360
- .data(currentNodes, function(d){ return d.id; })
361
- .join("g")
362
- .attr("class", "node-group")
363
- .attr("cursor", "pointer")
364
- .call(dragBehavior);
365
-
366
- // Circle — Zep: r=10, drop-shadow, stroke-width 1
367
- nodeSelection.append("circle")
368
- .attr("r", function(d){
369
- if (d.nodeKind === "insight") return 6;
370
- if (d.type === "ghost") return 7;
371
- return 10;
372
- })
373
- .attr("fill", function(d){ return d.color; })
374
- .attr("stroke", "#e2e8f0")
375
- .attr("stroke-width", function(d){ return d.type === "ghost" ? 1 : 1; })
376
- .attr("filter", "url(#drop-shadow)")
377
- .attr("stroke-dasharray", function(d){ return d.type === "ghost" ? "2,2" : null; });
378
-
379
- // Insight count badge (white text inside node)
380
- nodeSelection.filter(function(d){ return d.nodeKind !== "insight" && d.insightCount > 0; })
381
- .append("text")
382
- .attr("class", "insight-badge")
383
- .attr("text-anchor", "middle")
384
- .attr("dominant-baseline", "central")
385
- .attr("font-size", "8px")
386
- .attr("font-weight", "700")
387
- .attr("fill", "#fff")
388
- .attr("pointer-events", "none")
389
- .text(function(d){ return d.insightCount; });
390
-
391
- // Label — Zep: x=15, font-size 12px, font-weight 500
392
- // Hidden until zoom >= LABEL_ZOOM_THRESHOLD
393
- nodeSelection.append("text")
394
- .attr("x", 15)
395
- .attr("y", "0.3em")
396
- .attr("text-anchor", "start")
397
- .attr("fill", "#e2e8f0")
398
- .attr("font-weight", "500")
399
- .attr("font-size", "12px")
400
- .attr("pointer-events", "none")
401
- .attr("display", currentZoomScale >= LABEL_ZOOM_THRESHOLD ? null : "none")
402
- .text(function(d){
403
- var name = d.name || d.id;
404
- return name.length > 28 ? name.substring(0, 26) + ".." : name;
405
- });
406
-
407
- // Click handler
408
- nodeSelection.on("click", function(event, d){
409
- event.stopPropagation();
410
- handleNodeClick(d);
411
- });
412
-
413
- // Hover handlers
414
- nodeSelection.on("mouseenter", function(event, d){
415
- d3.select(this).select("circle")
416
- .attr("stroke", "#60a5fa")
417
- .attr("stroke-width", 3);
418
- }).on("mouseleave", function(event, d){
419
- d3.select(this).select("circle")
420
- .attr("stroke", "#e2e8f0")
421
- .attr("stroke-width", 1);
422
- applyVisualState();
423
- });
424
- }
425
-
426
- // ── Drag behavior — exact Zep pattern ──
427
- var dragBehavior = d3.drag()
428
- .on("start", function(event){
429
- if (!event.active) simulation.velocityDecay(0.7).alphaDecay(0.1).alphaTarget(0.1).restart();
430
- event.subject.fx = event.subject.x;
431
- event.subject.fy = event.subject.y;
432
- d3.select(this).select("circle").attr("stroke", "#60a5fa").attr("stroke-width", 3);
433
- })
434
- .on("drag", function(event){
435
- event.subject.fx = event.x;
436
- event.subject.fy = event.y;
437
- })
438
- .on("end", function(event){
439
- if (!event.active) simulation.velocityDecay(0.4).alphaDecay(0.05).alphaTarget(0);
440
- event.subject.fx = event.x;
441
- event.subject.fy = event.y;
442
- d3.select(this).select("circle").attr("stroke", "#e2e8f0").attr("stroke-width", 1);
443
- });
444
-
445
- // ══════════════════════════════════════════════════════════
446
- // TICK — update positions (Zep: quadratic Bézier paths)
447
- // ══════════════════════════════════════════════════════════
448
- simulation.on("tick", function(){
449
- if (!linkSelection || !nodeSelection) return;
450
-
451
- linkSelection.each(function(d){
452
- var el = d3.select(this);
453
- var path = el.select("path");
454
- var labelGroup = el.select(".link-label");
455
-
456
- var sx = d.source.x, sy = d.source.y, tx = d.target.x, ty = d.target.y;
457
- if (sx == null || tx == null) return;
458
-
459
- // Self-referencing loop
460
- if (d.source.id === d.target.id) {
461
- var rx = 40, ry = 90, offset = ry + 20;
462
- var cx = sx, cy = sy - offset;
463
- path.attr("d", "M" + sx + "," + sy + " C" + (cx-rx) + "," + cy + " " + (cx+rx) + "," + cy + " " + sx + "," + sy);
464
- labelGroup.attr("transform", "translate(" + cx + "," + (cy-10) + ")");
465
- } else {
466
- // Quadratic Bézier — Zep's curve calculation
467
- var dx = tx - sx, dy = ty - sy;
468
- var dr = Math.sqrt(dx*dx + dy*dy) || 1;
469
- var midX = (sx + tx) / 2, midY = (sy + ty) / 2;
470
- var normalX = -dy / dr, normalY = dx / dr;
471
- var curveMag = dr * (d.curveStrength || 0);
472
- var controlX = midX + normalX * curveMag;
473
- var controlY = midY + normalY * curveMag;
474
- path.attr("d", "M" + sx + "," + sy + " Q" + controlX + "," + controlY + " " + tx + "," + ty);
475
-
476
- // Position label at midpoint of Bézier — Zep's getPointAtLength pattern
477
- var pathNode = path.node();
478
- if (pathNode && pathNode.getTotalLength) {
479
- var pathLen = pathNode.getTotalLength();
480
- var midPt = pathNode.getPointAtLength(pathLen / 2);
481
- if (midPt) {
482
- var angle = Math.atan2(ty - sy, tx - sx) * 180 / Math.PI;
483
- var rot = (angle > 90 || angle < -90) ? angle - 180 : angle;
484
- labelGroup.attr("transform", "translate(" + midPt.x + "," + midPt.y + ") rotate(" + rot + ")");
485
- }
486
- }
487
- }
488
-
489
- // Size the label background rect
490
- var text = labelGroup.select("text");
491
- var rect = labelGroup.select("rect");
492
- var textNode = text.node();
493
- if (textNode) {
494
- var bbox = textNode.getBBox();
495
- if (bbox.width > 0) {
496
- rect.attr("x", -bbox.width/2 - 6).attr("y", -bbox.height/2 - 4)
497
- .attr("width", bbox.width + 12).attr("height", bbox.height + 8);
498
- }
499
- }
500
- });
501
-
502
- // Update node positions — Zep: translate(x,y)
503
- nodeSelection.attr("transform", function(d){ return "translate(" + d.x + "," + d.y + ")"; });
504
- });
505
-
506
- // ── Initial render ──
507
- render();
508
-
509
- // ── Zoom-to-fit after simulation settles ──
510
- var hasZoomed = false;
511
- simulation.on("end", function(){
512
- if (hasZoomed) return;
513
- hasZoomed = true;
514
- zoomToFit();
515
- });
516
- // Fallback zoom-to-fit
517
- setTimeout(function(){ if (!hasZoomed) { hasZoomed = true; zoomToFit(); } }, 2000);
518
-
519
- function zoomToFit(duration) {
520
- duration = duration || 750;
521
- var bounds = g.node().getBBox();
522
- if (!bounds || bounds.width === 0) return;
523
- var fullW = width, fullH = height;
524
- var midX = bounds.x + bounds.width / 2;
525
- var midY = bounds.y + bounds.height / 2;
526
- var scale = 0.65 * Math.min(fullW / bounds.width, fullH / bounds.height);
527
- if (!isFinite(scale) || !isFinite(midX)) return;
528
- var transform = d3.zoomIdentity
529
- .translate(fullW/2 - midX*scale, fullH/2 - midY*scale)
530
- .scale(scale);
531
- svg.transition().duration(duration).ease(d3.easeCubicInOut).call(zoomBehavior.transform, transform);
532
- }
533
-
534
- // ══════════════════════════════════════════════════════════
535
- // VISUAL STATE — focus/search dimming
536
- // ══════════════════════════════════════════════════════════
537
- function applyVisualState() {
538
- if (!nodeSelection || !linkSelection) return;
539
-
540
- nodeSelection.select("circle")
541
- .attr("fill", function(d){
542
- if (focusedNodeId && !focusedSet[d.id]) return "#1e293b";
543
- if (searchActive && !searchMatches[d.id]) return "#1e293b";
544
- return d.color;
545
- })
546
- .attr("stroke", function(d){
547
- if (focusedNodeId && focusedSet[d.id]) return "#60a5fa";
548
- return "#e2e8f0";
549
- })
550
- .attr("stroke-width", function(d){
551
- if (focusedNodeId && d.id === focusedNodeId) return 3;
552
- if (focusedNodeId && focusedSet[d.id]) return 2;
553
- return 1;
554
- })
555
- .attr("opacity", function(d){
556
- if (focusedNodeId && !focusedSet[d.id]) return 0.15;
557
- if (searchActive && !searchMatches[d.id]) return 0.15;
558
- return 1;
559
- });
560
-
561
- nodeSelection.selectAll("text")
562
- .attr("opacity", function(d){
563
- if (focusedNodeId && !focusedSet[d.id]) return 0.1;
564
- if (searchActive && !searchMatches[d.id]) return 0.1;
565
- return 1;
566
- });
567
-
568
- linkSelection.select("path")
569
- .attr("stroke", function(d){
570
- var sid = typeof d.source === "object" ? d.source.id : d.source;
571
- var tid = typeof d.target === "object" ? d.target.id : d.target;
572
- if (focusedNodeId) {
573
- if (focusedSet[sid] && focusedSet[tid]) return d.color;
574
- return "#0f172a";
575
- }
576
- return d.color;
577
- })
578
- .attr("stroke-opacity", function(d){
579
- var sid = typeof d.source === "object" ? d.source.id : d.source;
580
- var tid = typeof d.target === "object" ? d.target.id : d.target;
581
- if (focusedNodeId && !(focusedSet[sid] && focusedSet[tid])) return 0.05;
582
- if (searchActive && !(searchMatches[sid] && searchMatches[tid])) return 0.05;
583
- return 0.6;
584
- })
585
- .attr("stroke-width", function(d){
586
- var sid = typeof d.source === "object" ? d.source.id : d.source;
587
- var tid = typeof d.target === "object" ? d.target.id : d.target;
588
- if (focusedNodeId && focusedSet[sid] && focusedSet[tid]) return 2;
589
- return 1;
590
- });
591
-
592
- linkSelection.select(".link-label")
593
- .attr("opacity", function(d){
594
- var sid = typeof d.source === "object" ? d.source.id : d.source;
595
- var tid = typeof d.target === "object" ? d.target.id : d.target;
596
- if (focusedNodeId && !(focusedSet[sid] && focusedSet[tid])) return 0;
597
- if (searchActive && !(searchMatches[sid] && searchMatches[tid])) return 0;
598
- return 1;
599
- });
600
- }
601
-
602
- // ══════════════════════════════════════════════════════════
603
- // NODE CLICK — focus, expand insights, zoom to neighborhood
604
- // ══════════════════════════════════════════════════════════
605
- var panel = document.getElementById("detail-panel");
606
- var detailName = document.getElementById("detail-name");
607
- var detailBody = document.getElementById("detail-body");
608
- document.getElementById("detail-close").addEventListener("click", function(){ unfocus(); });
609
-
610
- function unfocus() {
611
- panel.classList.remove("open");
612
- expandedEntities = {};
613
- focusedNodeId = null;
614
- focusedSet = {};
615
- searchActive = false;
616
- searchMatches = {};
617
- rebuildAndRestart();
618
- applyVisualState();
619
- }
620
-
621
- function handleNodeClick(d) {
622
- // Toggle focus
623
- if (focusedNodeId === d.id) {
624
- unfocus();
625
- return;
626
- }
627
-
628
- focusedNodeId = d.id;
629
- focusedSet = {};
630
- focusedSet[d.id] = true;
631
-
632
- // Add 1st-degree neighbors
633
- currentLinks.forEach(function(l){
634
- var sid = typeof l.source === "object" ? l.source.id : l.source;
635
- var tid = typeof l.target === "object" ? l.target.id : l.target;
636
- if (sid === d.id) focusedSet[tid] = true;
637
- if (tid === d.id) focusedSet[sid] = true;
638
- });
639
-
640
- if (d.nodeKind === "insight") {
641
- showInsightDetail(d);
642
- } else {
643
- // Toggle insight expansion
644
- expandedEntities = {};
645
- if (insightsByEntity[d.id] && insightsByEntity[d.id].length > 0) {
646
- expandedEntities[d.id] = true;
647
- }
648
- showEntityDetail(d);
649
- rebuildAndRestart();
650
- // After rebuild, include new insight nodes in focusedSet
651
- currentNodes.forEach(function(n){
652
- if (n.nodeKind === "insight") focusedSet[n.id] = true;
653
- });
654
- }
655
-
656
- applyVisualState();
657
- // Delay zoom so simulation can position newly-added insight nodes
658
- setTimeout(function(){ zoomToNeighborhood(d); }, 300);
659
- }
660
-
661
- function rebuildAndRestart() {
662
- rebuildGraphArrays();
663
- simulation.nodes(currentNodes);
664
- simulation.force("link", d3.forceLink(currentLinks).id(function(d){ return d.id; }).distance(200).strength(0.2));
665
- simulation.alpha(0.3).restart();
666
- render();
667
- }
668
-
669
- // ── Zoom to neighborhood — exact Zep pattern ──
670
- function zoomToNeighborhood(d) {
671
- var connectedNodes = [d];
672
- currentNodes.forEach(function(n){
673
- if (n.id !== d.id && focusedSet[n.id] && n.x != null) connectedNodes.push(n);
674
- });
675
- if (connectedNodes.length < 1) return;
676
-
677
- var padding = 150;
678
- var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
679
- connectedNodes.forEach(function(n){
680
- if (n.x < minX) minX = n.x;
681
- if (n.y < minY) minY = n.y;
682
- if (n.x > maxX) maxX = n.x;
683
- if (n.y > maxY) maxY = n.y;
684
- });
685
- minX -= padding; minY -= padding; maxX += padding; maxY += padding;
686
- var bw = maxX - minX, bh = maxY - minY;
687
- var scale = Math.min(0.9 * Math.min(width / bw, height / bh), 1.5);
688
- var midX = (minX + maxX) / 2, midY = (minY + maxY) / 2;
689
- if (!isFinite(scale) || !isFinite(midX)) return;
690
- var transform = d3.zoomIdentity
691
- .translate(width/2 - midX*scale, height/2 - midY*scale)
692
- .scale(scale);
693
- svg.transition().duration(750).ease(d3.easeCubicInOut).call(zoomBehavior.transform, transform);
694
- }
695
-
696
- // ══════════════════════════════════════════════════════════
697
- // DETAIL PANEL
698
- // ══════════════════════════════════════════════════════════
699
- function addField(parent, labelText, valueText) {
700
- var field = document.createElement("div"); field.className = "field";
701
- var lbl = document.createElement("div"); lbl.className = "label"; lbl.textContent = labelText;
702
- var val = document.createElement("div"); val.className = "value"; val.textContent = valueText;
703
- field.appendChild(lbl); field.appendChild(val); parent.appendChild(field);
704
- }
705
-
706
- function showInsightDetail(d) {
707
- detailName.textContent = d.primary_attribute || "Insight";
708
- while (detailBody.firstChild) detailBody.removeChild(detailBody.firstChild);
709
- addField(detailBody, "Kind", "Insight (" + d.type + ")");
710
- addField(detailBody, "Type", d.primary_attribute || "");
711
- if (d.confidence != null) addField(detailBody, "Confidence", Math.round(d.confidence * 100) + "%");
712
- addField(detailBody, "Content", d.fullContent || d.name);
713
- panel.classList.add("open");
714
- }
715
-
716
- function showEntityDetail(d) {
717
- detailName.textContent = d.name || d.id;
718
- while (detailBody.firstChild) detailBody.removeChild(detailBody.firstChild);
719
- addField(detailBody, "Type", d.type || "");
720
- if (d.primary_attribute) addField(detailBody, "Primary", d.primary_attribute);
721
- if (d.created_at) addField(detailBody, "Created", d.created_at);
722
-
723
- // Summary card
724
- if (d.summary) {
725
- var summaryField = document.createElement("div"); summaryField.className = "field";
726
- var summaryLbl = document.createElement("div"); summaryLbl.className = "label"; summaryLbl.textContent = "Summary";
727
- summaryField.appendChild(summaryLbl);
728
- var summaryVal = document.createElement("div"); summaryVal.className = "value";
729
- summaryVal.style.cssText = "font-size:12px;line-height:1.6;color:#94a3b8;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word";
730
- summaryVal.textContent = d.summary;
731
- summaryField.appendChild(summaryVal); detailBody.appendChild(summaryField);
732
- }
733
-
734
- // Connections
735
- var connCount = 0;
736
- var connectedList = [];
737
- var nodeMap = {};
738
- entityNodes.forEach(function(n){ nodeMap[n.id] = n; });
739
- baseLinks.forEach(function(l){
740
- if (l.source === d.id || (typeof l.source === "object" && l.source.id === d.id)) { connCount++; connectedList.push(typeof l.target === "object" ? l.target.id : l.target); }
741
- if (l.target === d.id || (typeof l.target === "object" && l.target.id === d.id)) { connCount++; connectedList.push(typeof l.source === "object" ? l.source.id : l.source); }
742
- });
743
- addField(detailBody, "Connections", String(connCount));
744
-
745
- if (connectedList.length > 0) {
746
- var field = document.createElement("div"); field.className = "field";
747
- var lbl = document.createElement("div"); lbl.className = "label"; lbl.textContent = "Connected to";
748
- field.appendChild(lbl);
749
- var val = document.createElement("div"); val.className = "value";
750
- connectedList.slice(0, 20).forEach(function(cid){
751
- var line = document.createElement("div");
752
- var cn = nodeMap[cid];
753
- line.textContent = cn ? cn.name : cid;
754
- val.appendChild(line);
755
- });
756
- if (connectedList.length > 20) {
757
- var more = document.createElement("em");
758
- more.textContent = "...and " + (connectedList.length - 20) + " more";
759
- val.appendChild(more);
760
- }
761
- field.appendChild(val); detailBody.appendChild(field);
762
- }
763
-
764
- // Insights in panel
765
- var panelInsights = insightsMap[d.id] || [];
766
- if (panelInsights.length > 0) {
767
- var insightField = document.createElement("div"); insightField.className = "field";
768
- var insightLbl = document.createElement("div"); insightLbl.className = "label";
769
- insightLbl.textContent = "Insights (" + panelInsights.length + ")";
770
- insightField.appendChild(insightLbl);
771
- panelInsights.forEach(function(ins){
772
- var card = document.createElement("div"); card.className = "insight-card";
773
- var badge = document.createElement("span"); badge.className = "insight-type"; badge.textContent = ins.type;
774
- card.appendChild(badge);
775
- var conf = document.createElement("span"); conf.className = "insight-confidence";
776
- conf.textContent = Math.round(ins.confidence * 100) + "%";
777
- card.appendChild(conf);
778
- var content = document.createElement("div"); content.className = "insight-content"; content.textContent = ins.content;
779
- card.appendChild(content);
780
- insightField.appendChild(card);
781
- });
782
- detailBody.appendChild(insightField);
783
- }
784
-
785
- panel.classList.add("open");
786
- }
787
-
788
- // ══════════════════════════════════════════════════════════
789
- // SEARCH — highlight + zoom
790
- // ══════════════════════════════════════════════════════════
791
- var searchBox = document.getElementById("search-box");
792
- var searchResultsEl = document.createElement("div");
793
- searchResultsEl.id = "search-results";
794
- searchResultsEl.style.cssText = "position:fixed;top:52px;left:16px;z-index:10;font-size:12px;color:#64748b;padding:0 4px;display:none";
795
- document.body.appendChild(searchResultsEl);
796
-
797
- var searchTimer = null;
798
- searchBox.addEventListener("input", function(){
799
- if (searchTimer) clearTimeout(searchTimer);
800
- searchTimer = setTimeout(function(){
801
- var q = searchBox.value.trim().toLowerCase();
802
- searchMatches = {};
803
- searchActive = false;
804
- focusedNodeId = null;
805
- focusedSet = {};
806
- searchResultsEl.style.display = "none";
807
- if (q) {
808
- searchActive = true;
809
- var directMatches = [];
810
- currentNodes.forEach(function(n){
811
- var name = (n.name || n.id || "").toLowerCase();
812
- var type = (n.type || "").toLowerCase();
813
- var primary = (n.primary_attribute || "").toLowerCase();
814
- if (name.indexOf(q) >= 0 || type.indexOf(q) >= 0 || primary.indexOf(q) >= 0) {
815
- searchMatches[n.id] = true;
816
- directMatches.push(n);
817
- }
818
- });
819
- // 1st-degree neighbors
820
- currentLinks.forEach(function(l){
821
- var sid = typeof l.source === "object" ? l.source.id : l.source;
822
- var tid = typeof l.target === "object" ? l.target.id : l.target;
823
- if (searchMatches[sid]) searchMatches[tid] = true;
824
- if (searchMatches[tid]) searchMatches[sid] = true;
825
- });
826
- searchResultsEl.textContent = directMatches.length + " result" + (directMatches.length !== 1 ? "s" : "");
827
- searchResultsEl.style.display = "block";
828
- // Zoom to matches
829
- if (directMatches.length === 1 && directMatches[0].x != null) {
830
- var t = d3.zoomIdentity.translate(width/2 - directMatches[0].x*2, height/2 - directMatches[0].y*2).scale(2);
831
- svg.transition().duration(400).call(zoomBehavior.transform, t);
832
- } else if (directMatches.length > 1) {
833
- var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
834
- directMatches.forEach(function(n){
835
- if (n.x != null) { if (n.x < minX) minX = n.x; if (n.x > maxX) maxX = n.x; if (n.y < minY) minY = n.y; if (n.y > maxY) maxY = n.y; }
836
- });
837
- var cx = (minX+maxX)/2, cy = (minY+maxY)/2;
838
- var bw = maxX-minX+200, bh = maxY-minY+200;
839
- var z = Math.min(width/bw, height/bh, 4);
840
- var t2 = d3.zoomIdentity.translate(width/2-cx*z, height/2-cy*z).scale(Math.max(z, 0.3));
841
- svg.transition().duration(400).call(zoomBehavior.transform, t2);
842
- }
843
- }
844
- applyVisualState();
845
- }, 150);
846
- });
847
-
848
- // ── Handle window resize ──
849
- window.addEventListener("resize", function(){
850
- width = window.innerWidth;
851
- height = window.innerHeight;
852
- svg.attr("width", width).attr("height", height).attr("viewBox", "0 0 " + width + " " + height);
853
- });
854
- })();
855
- </script>
856
- </body>
857
- </html>`;
858
- }
859
- //# sourceMappingURL=graph-html.js.map