stellavault 0.1.0 → 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 (385) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/bin/ekh.js +2 -2
  3. package/packages/cli/dist/commands/federate-cmd.js +61 -31
  4. package/packages/core/dist/api/dashboard.d.ts +3 -0
  5. package/packages/core/{src/api/dashboard.ts → dist/api/dashboard.js} +8 -11
  6. package/packages/core/dist/api/graph-data.d.ts +11 -0
  7. package/packages/core/dist/api/graph-data.js +255 -0
  8. package/packages/core/dist/api/pwa.d.ts +3 -0
  9. package/packages/core/{src/api/pwa.ts → dist/api/pwa.js} +27 -32
  10. package/packages/core/dist/api/server.d.ts +16 -0
  11. package/packages/core/dist/api/server.js +647 -0
  12. package/packages/core/dist/capture/voice.d.ts +24 -0
  13. package/packages/core/dist/capture/voice.js +135 -0
  14. package/packages/core/{src/cloud/index.ts → dist/cloud/index.d.ts} +1 -0
  15. package/packages/core/dist/cloud/index.js +2 -0
  16. package/packages/core/dist/cloud/sync.d.ts +29 -0
  17. package/packages/core/dist/cloud/sync.js +137 -0
  18. package/packages/core/dist/config.d.ts +27 -0
  19. package/packages/core/dist/config.js +55 -0
  20. package/packages/core/dist/federation/credits.d.ts +26 -0
  21. package/packages/core/dist/federation/credits.js +56 -0
  22. package/packages/core/dist/federation/identity.d.ts +14 -0
  23. package/packages/core/dist/federation/identity.js +74 -0
  24. package/packages/core/{src/federation/index.ts → dist/federation/index.d.ts} +1 -2
  25. package/packages/core/dist/federation/index.js +5 -0
  26. package/packages/core/dist/federation/node.d.ts +31 -0
  27. package/packages/core/dist/federation/node.js +216 -0
  28. package/packages/core/dist/federation/privacy.d.ts +8 -0
  29. package/packages/core/dist/federation/privacy.js +40 -0
  30. package/packages/core/dist/federation/reputation.d.ts +37 -0
  31. package/packages/core/dist/federation/reputation.js +139 -0
  32. package/packages/core/dist/federation/search.d.ts +19 -0
  33. package/packages/core/dist/federation/search.js +101 -0
  34. package/packages/core/dist/federation/sharing.d.ts +72 -0
  35. package/packages/core/dist/federation/sharing.js +246 -0
  36. package/packages/core/dist/federation/trust.d.ts +15 -0
  37. package/packages/core/dist/federation/trust.js +60 -0
  38. package/packages/core/dist/federation/types.d.ts +40 -0
  39. package/packages/core/dist/federation/types.js +3 -0
  40. package/packages/core/dist/i18n/index.d.ts +6 -0
  41. package/packages/core/dist/i18n/index.js +81 -0
  42. package/packages/core/{src/index.ts → dist/index.d.ts} +48 -67
  43. package/packages/core/dist/index.js +69 -0
  44. package/packages/core/dist/indexer/chunker.d.ts +14 -0
  45. package/packages/core/dist/indexer/chunker.js +148 -0
  46. package/packages/core/dist/indexer/embedder.d.ts +8 -0
  47. package/packages/core/dist/indexer/embedder.js +3 -0
  48. package/packages/core/dist/indexer/index.d.ts +28 -0
  49. package/packages/core/dist/indexer/index.js +74 -0
  50. package/packages/core/dist/indexer/local-embedder.d.ts +3 -0
  51. package/packages/core/dist/indexer/local-embedder.js +29 -0
  52. package/packages/core/dist/indexer/scanner.d.ts +11 -0
  53. package/packages/core/dist/indexer/scanner.js +137 -0
  54. package/packages/core/dist/indexer/watcher.d.ts +19 -0
  55. package/packages/core/dist/indexer/watcher.js +49 -0
  56. package/packages/core/dist/intelligence/contradiction-detector.d.ts +20 -0
  57. package/packages/core/dist/intelligence/contradiction-detector.js +115 -0
  58. package/packages/core/dist/intelligence/decay-engine.d.ts +27 -0
  59. package/packages/core/dist/intelligence/decay-engine.js +190 -0
  60. package/packages/core/dist/intelligence/duplicate-detector.d.ts +20 -0
  61. package/packages/core/dist/intelligence/duplicate-detector.js +55 -0
  62. package/packages/core/dist/intelligence/fsrs.d.ts +43 -0
  63. package/packages/core/dist/intelligence/fsrs.js +70 -0
  64. package/packages/core/dist/intelligence/gap-detector.d.ts +25 -0
  65. package/packages/core/dist/intelligence/gap-detector.js +78 -0
  66. package/packages/core/dist/intelligence/learning-path.d.ts +31 -0
  67. package/packages/core/dist/intelligence/learning-path.js +53 -0
  68. package/packages/core/dist/intelligence/notifications.d.ts +31 -0
  69. package/packages/core/dist/intelligence/notifications.js +65 -0
  70. package/packages/core/dist/intelligence/predictive-gaps.d.ts +14 -0
  71. package/packages/core/dist/intelligence/predictive-gaps.js +74 -0
  72. package/packages/core/dist/intelligence/semantic-versioning.d.ts +37 -0
  73. package/packages/core/dist/intelligence/semantic-versioning.js +68 -0
  74. package/packages/core/dist/intelligence/types.d.ts +28 -0
  75. package/packages/core/dist/intelligence/types.js +3 -0
  76. package/packages/core/dist/mcp/custom-tools.d.ts +29 -0
  77. package/packages/core/dist/mcp/custom-tools.js +70 -0
  78. package/packages/core/{src/mcp/index.ts → dist/mcp/index.d.ts} +1 -0
  79. package/packages/core/dist/mcp/index.js +2 -0
  80. package/packages/core/dist/mcp/server.d.ts +49 -0
  81. package/packages/core/dist/mcp/server.js +133 -0
  82. package/packages/core/dist/mcp/tools/agentic-graph.d.ts +87 -0
  83. package/packages/core/dist/mcp/tools/agentic-graph.js +88 -0
  84. package/packages/core/dist/mcp/tools/brief.d.ts +31 -0
  85. package/packages/core/dist/mcp/tools/brief.js +39 -0
  86. package/packages/core/dist/mcp/tools/decay.d.ts +33 -0
  87. package/packages/core/dist/mcp/tools/decay.js +32 -0
  88. package/packages/core/dist/mcp/tools/decision-journal.d.ts +78 -0
  89. package/packages/core/dist/mcp/tools/decision-journal.js +79 -0
  90. package/packages/core/dist/mcp/tools/export.d.ts +29 -0
  91. package/packages/core/dist/mcp/tools/export.js +60 -0
  92. package/packages/core/dist/mcp/tools/federated-search.d.ts +29 -0
  93. package/packages/core/dist/mcp/tools/federated-search.js +36 -0
  94. package/packages/core/dist/mcp/tools/generate-claude-md.d.ts +35 -0
  95. package/packages/core/dist/mcp/tools/generate-claude-md.js +107 -0
  96. package/packages/core/dist/mcp/tools/get-document.d.ts +35 -0
  97. package/packages/core/dist/mcp/tools/get-document.js +25 -0
  98. package/packages/core/dist/mcp/tools/get-related.d.ts +32 -0
  99. package/packages/core/dist/mcp/tools/get-related.js +33 -0
  100. package/packages/core/dist/mcp/tools/learning-path.d.ts +23 -0
  101. package/packages/core/dist/mcp/tools/learning-path.js +45 -0
  102. package/packages/core/dist/mcp/tools/list-topics.d.ts +15 -0
  103. package/packages/core/dist/mcp/tools/list-topics.js +18 -0
  104. package/packages/core/dist/mcp/tools/search.d.ts +39 -0
  105. package/packages/core/dist/mcp/tools/search.js +29 -0
  106. package/packages/core/dist/mcp/tools/snapshot.d.ts +47 -0
  107. package/packages/core/dist/mcp/tools/snapshot.js +84 -0
  108. package/packages/core/dist/multi-vault/index.d.ts +26 -0
  109. package/packages/core/dist/multi-vault/index.js +80 -0
  110. package/packages/core/dist/pack/creator.d.ts +21 -0
  111. package/packages/core/dist/pack/creator.js +105 -0
  112. package/packages/core/dist/pack/exporter.d.ts +4 -0
  113. package/packages/core/dist/pack/exporter.js +18 -0
  114. package/packages/core/dist/pack/importer.d.ts +10 -0
  115. package/packages/core/dist/pack/importer.js +55 -0
  116. package/packages/core/{src/pack/index.ts → dist/pack/index.d.ts} +1 -0
  117. package/packages/core/dist/pack/index.js +5 -0
  118. package/packages/core/dist/pack/marketplace.d.ts +14 -0
  119. package/packages/core/dist/pack/marketplace.js +90 -0
  120. package/packages/core/dist/pack/pii-masker.d.ts +7 -0
  121. package/packages/core/dist/pack/pii-masker.js +29 -0
  122. package/packages/core/dist/pack/types.d.ts +36 -0
  123. package/packages/core/dist/pack/types.js +3 -0
  124. package/packages/core/dist/plugins/index.d.ts +35 -0
  125. package/packages/core/dist/plugins/index.js +57 -0
  126. package/packages/core/dist/plugins/webhooks.d.ts +30 -0
  127. package/packages/core/dist/plugins/webhooks.js +79 -0
  128. package/packages/core/dist/search/bm25.d.ts +4 -0
  129. package/packages/core/dist/search/bm25.js +10 -0
  130. package/packages/core/dist/search/index.d.ts +13 -0
  131. package/packages/core/dist/search/index.js +63 -0
  132. package/packages/core/dist/search/rrf.d.ts +7 -0
  133. package/packages/core/dist/search/rrf.js +21 -0
  134. package/packages/core/dist/search/semantic.d.ts +5 -0
  135. package/packages/core/dist/search/semantic.js +6 -0
  136. package/packages/core/{src/store/index.ts → dist/store/index.d.ts} +1 -0
  137. package/packages/core/dist/store/index.js +2 -0
  138. package/packages/core/dist/store/sqlite-vec.d.ts +6 -0
  139. package/packages/core/dist/store/sqlite-vec.js +251 -0
  140. package/packages/core/dist/store/types.d.ts +20 -0
  141. package/packages/core/dist/store/types.js +3 -0
  142. package/packages/core/dist/team/index.d.ts +25 -0
  143. package/packages/core/dist/team/index.js +97 -0
  144. package/packages/core/dist/types/chunk.d.ts +23 -0
  145. package/packages/core/dist/types/chunk.js +3 -0
  146. package/packages/core/dist/types/document.d.ts +23 -0
  147. package/packages/core/dist/types/document.js +3 -0
  148. package/packages/core/dist/types/graph.d.ts +39 -0
  149. package/packages/core/dist/types/graph.js +3 -0
  150. package/packages/core/dist/types/index.d.ts +5 -0
  151. package/packages/core/dist/types/index.js +2 -0
  152. package/packages/core/dist/types/search.d.ts +39 -0
  153. package/packages/core/dist/types/search.js +3 -0
  154. package/packages/core/dist/utils/retry.d.ts +25 -0
  155. package/packages/core/dist/utils/retry.js +59 -0
  156. package/memory/MEMORY.md +0 -25
  157. package/packages/cli/dist/commands/brief-cmd.d.ts.map +0 -1
  158. package/packages/cli/dist/commands/brief-cmd.js.map +0 -1
  159. package/packages/cli/dist/commands/capture-cmd.d.ts.map +0 -1
  160. package/packages/cli/dist/commands/capture-cmd.js.map +0 -1
  161. package/packages/cli/dist/commands/card-cmd.d.ts.map +0 -1
  162. package/packages/cli/dist/commands/card-cmd.js.map +0 -1
  163. package/packages/cli/dist/commands/clip-cmd.d.ts.map +0 -1
  164. package/packages/cli/dist/commands/clip-cmd.js.map +0 -1
  165. package/packages/cli/dist/commands/cloud-cmd.d.ts.map +0 -1
  166. package/packages/cli/dist/commands/cloud-cmd.js.map +0 -1
  167. package/packages/cli/dist/commands/contradictions-cmd.d.ts.map +0 -1
  168. package/packages/cli/dist/commands/contradictions-cmd.js.map +0 -1
  169. package/packages/cli/dist/commands/decay-cmd.d.ts.map +0 -1
  170. package/packages/cli/dist/commands/decay-cmd.js.map +0 -1
  171. package/packages/cli/dist/commands/digest-cmd.d.ts.map +0 -1
  172. package/packages/cli/dist/commands/digest-cmd.js.map +0 -1
  173. package/packages/cli/dist/commands/duplicates-cmd.d.ts.map +0 -1
  174. package/packages/cli/dist/commands/duplicates-cmd.js.map +0 -1
  175. package/packages/cli/dist/commands/federate-cmd.d.ts.map +0 -1
  176. package/packages/cli/dist/commands/federate-cmd.js.map +0 -1
  177. package/packages/cli/dist/commands/gaps-cmd.d.ts.map +0 -1
  178. package/packages/cli/dist/commands/gaps-cmd.js.map +0 -1
  179. package/packages/cli/dist/commands/graph-cmd.d.ts.map +0 -1
  180. package/packages/cli/dist/commands/graph-cmd.js.map +0 -1
  181. package/packages/cli/dist/commands/index-cmd.d.ts.map +0 -1
  182. package/packages/cli/dist/commands/index-cmd.js.map +0 -1
  183. package/packages/cli/dist/commands/init-cmd.d.ts.map +0 -1
  184. package/packages/cli/dist/commands/init-cmd.js.map +0 -1
  185. package/packages/cli/dist/commands/learn-cmd.d.ts.map +0 -1
  186. package/packages/cli/dist/commands/learn-cmd.js.map +0 -1
  187. package/packages/cli/dist/commands/pack-cmd.d.ts.map +0 -1
  188. package/packages/cli/dist/commands/pack-cmd.js.map +0 -1
  189. package/packages/cli/dist/commands/review-cmd.d.ts.map +0 -1
  190. package/packages/cli/dist/commands/review-cmd.js.map +0 -1
  191. package/packages/cli/dist/commands/search-cmd.d.ts.map +0 -1
  192. package/packages/cli/dist/commands/search-cmd.js.map +0 -1
  193. package/packages/cli/dist/commands/serve-cmd.d.ts.map +0 -1
  194. package/packages/cli/dist/commands/serve-cmd.js.map +0 -1
  195. package/packages/cli/dist/commands/status-cmd.d.ts.map +0 -1
  196. package/packages/cli/dist/commands/status-cmd.js.map +0 -1
  197. package/packages/cli/dist/commands/sync-cmd.d.ts.map +0 -1
  198. package/packages/cli/dist/commands/sync-cmd.js.map +0 -1
  199. package/packages/cli/dist/commands/vault-cmd.d.ts.map +0 -1
  200. package/packages/cli/dist/commands/vault-cmd.js.map +0 -1
  201. package/packages/cli/dist/index.d.ts.map +0 -1
  202. package/packages/cli/dist/index.js.map +0 -1
  203. package/packages/cli/src/commands/brief-cmd.ts +0 -87
  204. package/packages/cli/src/commands/capture-cmd.ts +0 -34
  205. package/packages/cli/src/commands/card-cmd.ts +0 -29
  206. package/packages/cli/src/commands/clip-cmd.ts +0 -172
  207. package/packages/cli/src/commands/cloud-cmd.ts +0 -75
  208. package/packages/cli/src/commands/contradictions-cmd.ts +0 -41
  209. package/packages/cli/src/commands/decay-cmd.ts +0 -57
  210. package/packages/cli/src/commands/digest-cmd.ts +0 -89
  211. package/packages/cli/src/commands/duplicates-cmd.ts +0 -38
  212. package/packages/cli/src/commands/federate-cmd.ts +0 -236
  213. package/packages/cli/src/commands/gaps-cmd.ts +0 -40
  214. package/packages/cli/src/commands/graph-cmd.ts +0 -88
  215. package/packages/cli/src/commands/index-cmd.ts +0 -65
  216. package/packages/cli/src/commands/init-cmd.ts +0 -145
  217. package/packages/cli/src/commands/learn-cmd.ts +0 -56
  218. package/packages/cli/src/commands/pack-cmd.ts +0 -121
  219. package/packages/cli/src/commands/review-cmd.ts +0 -125
  220. package/packages/cli/src/commands/search-cmd.ts +0 -45
  221. package/packages/cli/src/commands/serve-cmd.ts +0 -17
  222. package/packages/cli/src/commands/status-cmd.ts +0 -37
  223. package/packages/cli/src/commands/sync-cmd.ts +0 -68
  224. package/packages/cli/src/commands/vault-cmd.ts +0 -64
  225. package/packages/cli/src/index.ts +0 -187
  226. package/packages/core/src/api/graph-data.ts +0 -286
  227. package/packages/core/src/api/server.ts +0 -660
  228. package/packages/core/src/capture/voice.ts +0 -168
  229. package/packages/core/src/cloud/sync.ts +0 -167
  230. package/packages/core/src/config.ts +0 -82
  231. package/packages/core/src/federation/credits.ts +0 -80
  232. package/packages/core/src/federation/hyperswarm.d.ts +0 -19
  233. package/packages/core/src/federation/identity.ts +0 -90
  234. package/packages/core/src/federation/node.ts +0 -235
  235. package/packages/core/src/federation/privacy.ts +0 -52
  236. package/packages/core/src/federation/reputation.ts +0 -202
  237. package/packages/core/src/federation/search.ts +0 -129
  238. package/packages/core/src/federation/sharing.ts +0 -165
  239. package/packages/core/src/federation/trust.ts +0 -76
  240. package/packages/core/src/federation/types.ts +0 -25
  241. package/packages/core/src/i18n/index.ts +0 -85
  242. package/packages/core/src/indexer/chunker.ts +0 -180
  243. package/packages/core/src/indexer/embedder.ts +0 -9
  244. package/packages/core/src/indexer/index.ts +0 -113
  245. package/packages/core/src/indexer/local-embedder.ts +0 -35
  246. package/packages/core/src/indexer/scanner.ts +0 -142
  247. package/packages/core/src/indexer/watcher.ts +0 -62
  248. package/packages/core/src/intelligence/contradiction-detector.ts +0 -134
  249. package/packages/core/src/intelligence/decay-engine.ts +0 -229
  250. package/packages/core/src/intelligence/duplicate-detector.ts +0 -71
  251. package/packages/core/src/intelligence/fsrs.ts +0 -79
  252. package/packages/core/src/intelligence/gap-detector.ts +0 -109
  253. package/packages/core/src/intelligence/learning-path.ts +0 -86
  254. package/packages/core/src/intelligence/notifications.ts +0 -106
  255. package/packages/core/src/intelligence/predictive-gaps.ts +0 -94
  256. package/packages/core/src/intelligence/semantic-versioning.ts +0 -97
  257. package/packages/core/src/intelligence/types.ts +0 -28
  258. package/packages/core/src/mcp/custom-tools.ts +0 -97
  259. package/packages/core/src/mcp/server.ts +0 -142
  260. package/packages/core/src/mcp/tools/agentic-graph.ts +0 -96
  261. package/packages/core/src/mcp/tools/brief.ts +0 -49
  262. package/packages/core/src/mcp/tools/decay.ts +0 -40
  263. package/packages/core/src/mcp/tools/decision-journal.ts +0 -95
  264. package/packages/core/src/mcp/tools/export.ts +0 -72
  265. package/packages/core/src/mcp/tools/federated-search.ts +0 -43
  266. package/packages/core/src/mcp/tools/generate-claude-md.ts +0 -130
  267. package/packages/core/src/mcp/tools/get-document.ts +0 -26
  268. package/packages/core/src/mcp/tools/get-related.ts +0 -41
  269. package/packages/core/src/mcp/tools/learning-path.ts +0 -52
  270. package/packages/core/src/mcp/tools/list-topics.ts +0 -20
  271. package/packages/core/src/mcp/tools/search.ts +0 -35
  272. package/packages/core/src/mcp/tools/snapshot.ts +0 -98
  273. package/packages/core/src/multi-vault/index.ts +0 -118
  274. package/packages/core/src/pack/creator.ts +0 -127
  275. package/packages/core/src/pack/exporter.ts +0 -21
  276. package/packages/core/src/pack/importer.ts +0 -82
  277. package/packages/core/src/pack/marketplace.ts +0 -103
  278. package/packages/core/src/pack/pii-masker.ts +0 -38
  279. package/packages/core/src/pack/types.ts +0 -39
  280. package/packages/core/src/plugins/index.ts +0 -100
  281. package/packages/core/src/plugins/webhooks.ts +0 -110
  282. package/packages/core/src/search/bm25.ts +0 -16
  283. package/packages/core/src/search/index.ts +0 -83
  284. package/packages/core/src/search/rrf.ts +0 -31
  285. package/packages/core/src/search/semantic.ts +0 -15
  286. package/packages/core/src/store/sqlite-vec.ts +0 -290
  287. package/packages/core/src/store/types.ts +0 -22
  288. package/packages/core/src/team/index.ts +0 -126
  289. package/packages/core/src/types/chunk.ts +0 -25
  290. package/packages/core/src/types/document.ts +0 -24
  291. package/packages/core/src/types/graph.ts +0 -44
  292. package/packages/core/src/types/index.ts +0 -15
  293. package/packages/core/src/types/search.ts +0 -38
  294. package/packages/core/src/utils/retry.ts +0 -85
  295. package/packages/core/tests/api-card.test.ts +0 -60
  296. package/packages/core/tests/api-routes.test.ts +0 -98
  297. package/packages/core/tests/bm25.test.ts +0 -87
  298. package/packages/core/tests/chunker.test.ts +0 -48
  299. package/packages/core/tests/cluster.test.ts +0 -75
  300. package/packages/core/tests/constellation.test.ts +0 -77
  301. package/packages/core/tests/export-utils.test.ts +0 -97
  302. package/packages/core/tests/fsrs.test.ts +0 -96
  303. package/packages/core/tests/gesture-detector.test.ts +0 -45
  304. package/packages/core/tests/graph-data.test.ts +0 -87
  305. package/packages/core/tests/layout.test.ts +0 -83
  306. package/packages/core/tests/mcp.test.ts +0 -148
  307. package/packages/core/tests/pack.test.ts +0 -127
  308. package/packages/core/tests/pii-masker.test.ts +0 -42
  309. package/packages/core/tests/profile-card.test.ts +0 -62
  310. package/packages/core/tests/rrf.test.ts +0 -29
  311. package/packages/core/tests/search-integration.test.ts +0 -139
  312. package/packages/core/tests/store.test.ts +0 -80
  313. package/packages/graph/click-result.png +0 -0
  314. package/packages/graph/index.html +0 -17
  315. package/packages/graph/package.json +0 -32
  316. package/packages/graph/src/App.tsx +0 -7
  317. package/packages/graph/src/api/client.ts +0 -39
  318. package/packages/graph/src/components/ClusterFilter.tsx +0 -73
  319. package/packages/graph/src/components/ConstellationView.tsx +0 -232
  320. package/packages/graph/src/components/ExportPanel.tsx +0 -177
  321. package/packages/graph/src/components/Graph3D.tsx +0 -230
  322. package/packages/graph/src/components/GraphEdges.tsx +0 -100
  323. package/packages/graph/src/components/GraphNodes.tsx +0 -386
  324. package/packages/graph/src/components/HealthDashboard.tsx +0 -173
  325. package/packages/graph/src/components/Layout.tsx +0 -214
  326. package/packages/graph/src/components/MotionOverlay.tsx +0 -81
  327. package/packages/graph/src/components/MotionToggle.tsx +0 -33
  328. package/packages/graph/src/components/MultiverseView.tsx +0 -286
  329. package/packages/graph/src/components/NodeDetail.tsx +0 -232
  330. package/packages/graph/src/components/PulseParticle.tsx +0 -232
  331. package/packages/graph/src/components/SearchBar.tsx +0 -107
  332. package/packages/graph/src/components/StarField.tsx +0 -197
  333. package/packages/graph/src/components/StatusBar.tsx +0 -53
  334. package/packages/graph/src/components/Timeline.tsx +0 -148
  335. package/packages/graph/src/components/ToolsPanel.tsx +0 -512
  336. package/packages/graph/src/components/Tooltip.tsx +0 -100
  337. package/packages/graph/src/components/TypeFilter.tsx +0 -131
  338. package/packages/graph/src/embed/EmbedGraph.tsx +0 -144
  339. package/packages/graph/src/hooks/useConstellationLOD.ts +0 -76
  340. package/packages/graph/src/hooks/useDecay.ts +0 -37
  341. package/packages/graph/src/hooks/useExport.ts +0 -165
  342. package/packages/graph/src/hooks/useGraph.ts +0 -69
  343. package/packages/graph/src/hooks/useKeyboardNav.ts +0 -122
  344. package/packages/graph/src/hooks/useLayout.ts +0 -45
  345. package/packages/graph/src/hooks/useMotion.ts +0 -120
  346. package/packages/graph/src/hooks/usePulse.ts +0 -58
  347. package/packages/graph/src/hooks/useSearch.ts +0 -71
  348. package/packages/graph/src/lib/constellation.ts +0 -107
  349. package/packages/graph/src/lib/export-utils.ts +0 -48
  350. package/packages/graph/src/lib/gesture-detector.ts +0 -123
  351. package/packages/graph/src/lib/layout.worker.ts +0 -153
  352. package/packages/graph/src/lib/motion-controller.ts +0 -83
  353. package/packages/graph/src/lib/profile-card.ts +0 -122
  354. package/packages/graph/src/main.tsx +0 -4
  355. package/packages/graph/src/stores/graph-store.ts +0 -155
  356. package/packages/graph/success.png +0 -0
  357. package/packages/graph/test-click.mjs +0 -49
  358. package/packages/graph/test-explore.mjs +0 -102
  359. package/packages/graph/test-final.mjs +0 -61
  360. package/packages/graph/test-graph.mjs +0 -139
  361. package/packages/graph/test-hover.mjs +0 -48
  362. package/packages/graph/test-pulse.mjs +0 -68
  363. package/packages/graph/test-screenshot.mjs +0 -56
  364. package/packages/graph/test-v2.mjs +0 -97
  365. package/packages/graph/vite.config.ts +0 -15
  366. package/packages/sync/.env.example +0 -11
  367. package/packages/sync/.sync-state.json +0 -317
  368. package/packages/sync/.upload-state.json +0 -1009
  369. package/packages/sync/create-stella-network-notion.mjs +0 -151
  370. package/packages/sync/create-stellavault-project-notion.mjs +0 -322
  371. package/packages/sync/logs/sync-2026-03-28.log +0 -6
  372. package/packages/sync/logs/sync-2026-03-29.log +0 -12
  373. package/packages/sync/logs/sync-2026-03-30.log +0 -6
  374. package/packages/sync/logs/sync-2026-03-31.log +0 -6
  375. package/packages/sync/logs/sync-2026-04-01.log +0 -6
  376. package/packages/sync/logs/sync-2026-04-02.log +0 -6
  377. package/packages/sync/package-lock.json +0 -373
  378. package/packages/sync/package.json +0 -16
  379. package/packages/sync/run-sync.bat +0 -18
  380. package/packages/sync/run-sync.mjs +0 -46
  381. package/packages/sync/setup-scheduler.mjs +0 -119
  382. package/packages/sync/structured-sync.mjs +0 -187
  383. package/packages/sync/sync-to-obsidian.mjs +0 -264
  384. package/packages/sync/upload-pdca-to-notion.mjs +0 -495
  385. package/tsconfig.base.json +0 -18
@@ -1,139 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { createSqliteVecStore } from '../src/store/sqlite-vec.js';
3
- import { createSearchEngine } from '../src/search/index.js';
4
- import type { VectorStore } from '../src/store/types.js';
5
- import type { Embedder } from '../src/indexer/embedder.js';
6
-
7
- const DIMS = 4;
8
-
9
- // 고정 벡터를 반환하는 테스트용 embedder
10
- function createMockEmbedder(): Embedder {
11
- return {
12
- modelName: 'test-mock',
13
- dimensions: DIMS,
14
- embed: async (text: string) => {
15
- // 간단한 결정적 벡터 생성: 텍스트 길이 기반
16
- const len = text.length;
17
- return [len % 3 / 3, len % 5 / 5, len % 7 / 7, len % 11 / 11];
18
- },
19
- embedBatch: async (texts: string[]) => {
20
- return Promise.all(texts.map(t => {
21
- const len = t.length;
22
- return [len % 3 / 3, len % 5 / 5, len % 7 / 7, len % 11 / 11];
23
- }));
24
- },
25
- };
26
- }
27
-
28
- let store: VectorStore;
29
- let embedder: Embedder;
30
-
31
- beforeEach(async () => {
32
- store = createSqliteVecStore(':memory:', DIMS);
33
- await store.initialize();
34
- embedder = createMockEmbedder();
35
-
36
- // 테스트 문서 3개 삽입
37
- await store.upsertDocument({
38
- id: 'doc-react', filePath: 'react-patterns.md', title: 'React 상태관리 패턴',
39
- content: 'React 상태관리 패턴에 대한 종합 가이드', frontmatter: {},
40
- tags: ['react', 'frontend'], lastModified: '2026-01-01', contentHash: 'r1',
41
- });
42
- await store.upsertChunks([{
43
- id: 'doc-react#0', documentId: 'doc-react',
44
- content: 'React useState useReducer 패턴 비교 분석',
45
- heading: 'React 상태관리', startLine: 1, endLine: 5, tokenCount: 10,
46
- embedding: [0.9, 0.1, 0.2, 0.1],
47
- }]);
48
-
49
- await store.upsertDocument({
50
- id: 'doc-auth', filePath: 'auth-design.md', title: 'OAuth 인증 설계',
51
- content: 'OAuth 2.0 인증 흐름 설계 문서', frontmatter: {},
52
- tags: ['auth', 'security'], lastModified: '2026-01-02', contentHash: 'a1',
53
- });
54
- await store.upsertChunks([{
55
- id: 'doc-auth#0', documentId: 'doc-auth',
56
- content: 'OAuth 2.0 Authorization Code Flow with PKCE',
57
- heading: 'OAuth 인증', startLine: 1, endLine: 5, tokenCount: 8,
58
- embedding: [0.1, 0.9, 0.1, 0.2],
59
- }]);
60
-
61
- await store.upsertDocument({
62
- id: 'doc-deploy', filePath: 'deploy-lessons.md', title: '배포 실패 교훈',
63
- content: '프로덕션 배포 중 발생한 장애 회고', frontmatter: {},
64
- tags: ['devops', 'lessons'], lastModified: '2026-01-03', contentHash: 'd1',
65
- });
66
- await store.upsertChunks([{
67
- id: 'doc-deploy#0', documentId: 'doc-deploy',
68
- content: '배포 실패 롤백 전략과 카나리 배포 교훈',
69
- heading: '배포 교훈', startLine: 1, endLine: 5, tokenCount: 12,
70
- embedding: [0.2, 0.1, 0.9, 0.1],
71
- }]);
72
- });
73
-
74
- afterEach(async () => {
75
- await store.close();
76
- });
77
-
78
- describe('Search Integration (BM25 + Semantic + RRF)', () => {
79
- it('자연어 쿼리로 결과 반환', async () => {
80
- const engine = createSearchEngine({ store, embedder });
81
- const results = await engine.search({ query: 'React 상태관리', limit: 5 });
82
-
83
- expect(results.length).toBeGreaterThan(0);
84
- // 각 결과에 필수 필드 존재
85
- for (const r of results) {
86
- expect(r.chunk).toBeDefined();
87
- expect(r.document).toBeDefined();
88
- expect(r.score).toBeGreaterThan(0);
89
- expect(r.highlights).toBeDefined();
90
- }
91
- });
92
-
93
- it('태그 필터링 동작', async () => {
94
- const engine = createSearchEngine({ store, embedder });
95
- const results = await engine.search({
96
- query: 'React 상태관리 OAuth 배포',
97
- limit: 10,
98
- tags: ['auth'],
99
- });
100
-
101
- // auth 태그가 있는 문서만 반환
102
- for (const r of results) {
103
- expect(r.document.tags).toContain('auth');
104
- }
105
- });
106
-
107
- it('limit 제한 동작', async () => {
108
- const engine = createSearchEngine({ store, embedder });
109
- const results = await engine.search({ query: 'React OAuth 배포', limit: 1 });
110
- expect(results.length).toBeLessThanOrEqual(1);
111
- });
112
-
113
- it('빈 쿼리도 에러 없이 처리', async () => {
114
- const engine = createSearchEngine({ store, embedder });
115
- const results = await engine.search({ query: '', limit: 5 });
116
- expect(Array.isArray(results)).toBe(true);
117
- });
118
-
119
- it('결과에 highlights 포함', async () => {
120
- const engine = createSearchEngine({ store, embedder });
121
- const results = await engine.search({ query: 'React', limit: 5 });
122
-
123
- const withHighlights = results.filter(r => r.highlights.length > 0);
124
- // BM25가 매칭하면 highlights가 있어야 함
125
- if (results.length > 0) {
126
- expect(withHighlights.length).toBeGreaterThanOrEqual(0);
127
- }
128
- });
129
-
130
- it('존재하지 않는 태그 필터 시 빈 결과', async () => {
131
- const engine = createSearchEngine({ store, embedder });
132
- const results = await engine.search({
133
- query: 'React',
134
- limit: 10,
135
- tags: ['nonexistent-tag'],
136
- });
137
- expect(results).toEqual([]);
138
- });
139
- });
@@ -1,80 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { createSqliteVecStore } from '../src/store/sqlite-vec.js';
3
- import type { VectorStore } from '../src/store/types.js';
4
-
5
- let store: VectorStore;
6
-
7
- beforeEach(async () => {
8
- store = createSqliteVecStore(':memory:', 4); // 4차원 (테스트용)
9
- await store.initialize();
10
- });
11
-
12
- afterEach(async () => {
13
- await store.close();
14
- });
15
-
16
- describe('VectorStore', () => {
17
- it('초기 상태 비어있음', async () => {
18
- const stats = await store.getStats();
19
- expect(stats.documentCount).toBe(0);
20
- expect(stats.chunkCount).toBe(0);
21
- });
22
-
23
- it('document + chunk upsert 및 조회', async () => {
24
- await store.upsertDocument({
25
- id: 'doc1', filePath: 'test.md', title: 'Test', content: 'Hello',
26
- frontmatter: {}, tags: ['test'], lastModified: '2026-01-01', contentHash: 'abc',
27
- });
28
- await store.upsertChunks([{
29
- id: 'doc1#0', documentId: 'doc1', content: 'Hello world',
30
- heading: 'Test', startLine: 1, endLine: 2, tokenCount: 3,
31
- embedding: [0.1, 0.2, 0.3, 0.4],
32
- }]);
33
-
34
- const doc = await store.getDocument('doc1');
35
- expect(doc).not.toBeNull();
36
- expect(doc!.title).toBe('Test');
37
-
38
- const chunk = await store.getChunk('doc1#0');
39
- expect(chunk).not.toBeNull();
40
- expect(chunk!.content).toBe('Hello world');
41
-
42
- const stats = await store.getStats();
43
- expect(stats.documentCount).toBe(1);
44
- expect(stats.chunkCount).toBe(1);
45
- });
46
-
47
- it('semantic search', async () => {
48
- await store.upsertDocument({
49
- id: 'doc1', filePath: 'a.md', title: 'A', content: 'A',
50
- frontmatter: {}, tags: [], lastModified: '2026-01-01', contentHash: 'a',
51
- });
52
- await store.upsertChunks([{
53
- id: 'doc1#0', documentId: 'doc1', content: 'Content A',
54
- heading: 'A', startLine: 1, endLine: 1, tokenCount: 2,
55
- embedding: [1.0, 0.0, 0.0, 0.0],
56
- }]);
57
-
58
- const results = await store.searchSemantic([1.0, 0.0, 0.0, 0.0], 5);
59
- expect(results.length).toBe(1);
60
- expect(results[0].chunkId).toBe('doc1#0');
61
- expect(results[0].score).toBeGreaterThan(0);
62
- });
63
-
64
- it('deleteByDocumentId', async () => {
65
- await store.upsertDocument({
66
- id: 'doc1', filePath: 'a.md', title: 'A', content: 'A',
67
- frontmatter: {}, tags: [], lastModified: '2026-01-01', contentHash: 'a',
68
- });
69
- await store.upsertChunks([{
70
- id: 'doc1#0', documentId: 'doc1', content: 'Content',
71
- heading: 'A', startLine: 1, endLine: 1, tokenCount: 1,
72
- embedding: [0.1, 0.2, 0.3, 0.4],
73
- }]);
74
-
75
- await store.deleteByDocumentId('doc1');
76
- expect(await store.getDocument('doc1')).toBeNull();
77
- const stats = await store.getStats();
78
- expect(stats.chunkCount).toBe(0);
79
- });
80
- });
Binary file
@@ -1,17 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Evan Knowledge Hub — 3D Knowledge Graph</title>
7
- <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
9
- html, body, #root { width: 100%; height: 100%; overflow: hidden; }
10
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0f; color: #e0e0e0; }
11
- </style>
12
- </head>
13
- <body>
14
- <div id="root"></div>
15
- <script type="module" src="/src/main.tsx"></script>
16
- </body>
17
- </html>
@@ -1,32 +0,0 @@
1
- {
2
- "name": "@stellavault/graph",
3
- "version": "0.1.0",
4
- "description": "Stellavault — 3D Neural Knowledge Graph Visualization",
5
- "type": "module",
6
- "private": true,
7
- "scripts": {
8
- "dev": "vite",
9
- "build": "tsc -b && vite build",
10
- "preview": "vite preview"
11
- },
12
- "dependencies": {
13
- "@mediapipe/camera_utils": "^0.3.1675466862",
14
- "@mediapipe/drawing_utils": "^0.3.1675466124",
15
- "@mediapipe/hands": "^0.4.1675469240",
16
- "@react-three/drei": "^10.0.0",
17
- "@react-three/fiber": "^9.0.0",
18
- "react": "^19.0.0",
19
- "react-dom": "^19.0.0",
20
- "react-markdown": "^10.0.0",
21
- "three": "^0.170.0",
22
- "zustand": "^5.0.0"
23
- },
24
- "devDependencies": {
25
- "@types/react": "^19.0.0",
26
- "@types/react-dom": "^19.0.0",
27
- "@types/three": "^0.170.0",
28
- "@vitejs/plugin-react": "^4.0.0",
29
- "typescript": "^5.7.0",
30
- "vite": "^6.0.0"
31
- }
32
- }
@@ -1,7 +0,0 @@
1
- import { Layout } from './components/Layout.js';
2
- import { useGraph } from './hooks/useGraph.js';
3
-
4
- export function App() {
5
- useGraph(); // 그래프 데이터 자동 로딩
6
- return <Layout />;
7
- }
@@ -1,39 +0,0 @@
1
- // Design Ref: §2.2 — API-UI 통신 (REST HTTP)
2
-
3
- const BASE = '/api';
4
-
5
- export async function fetchGraph() {
6
- const res = await fetch(`${BASE}/graph`);
7
- if (!res.ok) throw new Error(`Graph API error: ${res.status}`);
8
- return res.json();
9
- }
10
-
11
- export async function fetchSearch(query: string, limit = 10) {
12
- const res = await fetch(`${BASE}/search?q=${encodeURIComponent(query)}&limit=${limit}`);
13
- if (!res.ok) throw new Error(`Search API error: ${res.status}`);
14
- return res.json();
15
- }
16
-
17
- export async function fetchDocument(id: string) {
18
- const res = await fetch(`${BASE}/document/${encodeURIComponent(id)}`);
19
- if (!res.ok) throw new Error(`Document API error: ${res.status}`);
20
- return res.json();
21
- }
22
-
23
- export async function fetchStats() {
24
- const res = await fetch(`${BASE}/stats`);
25
- if (!res.ok) throw new Error(`Stats API error: ${res.status}`);
26
- return res.json();
27
- }
28
-
29
- export async function fetchHealth() {
30
- const res = await fetch(`${BASE}/health`);
31
- if (!res.ok) throw new Error(`Health API error: ${res.status}`);
32
- return res.json();
33
- }
34
-
35
- export async function fetchEmbed(apiUrl: string, max = 200) {
36
- const res = await fetch(`${apiUrl}/api/embed?max=${max}`);
37
- if (!res.ok) throw new Error(`Embed API error: ${res.status}`);
38
- return res.json();
39
- }
@@ -1,73 +0,0 @@
1
- // 클러스터 필터 — zustand store 기반
2
-
3
- import { useState } from 'react';
4
- import { useGraphStore } from '../stores/graph-store.js';
5
-
6
- export function ClusterFilter() {
7
- const clusters = useGraphStore((s) => s.clusters);
8
- const hiddenClusters = useGraphStore((s) => s.hiddenClusters);
9
- const toggleHiddenCluster = useGraphStore((s) => s.toggleHiddenCluster);
10
- const theme = useGraphStore((s) => s.theme);
11
- const isDark = theme === 'dark';
12
- const [open, setOpen] = useState(false);
13
-
14
- if (clusters.length === 0) return null;
15
-
16
- return (
17
- <div style={{ position: 'relative' }}>
18
- <button
19
- onClick={() => setOpen(!open)}
20
- style={{
21
- padding: '4px 10px', fontSize: '11px',
22
- border: `1px solid ${isDark ? 'rgba(100,120,255,0.15)' : 'rgba(0,0,0,0.12)'}`,
23
- borderRadius: '4px', cursor: 'pointer',
24
- background: open
25
- ? (isDark ? 'rgba(100,120,255,0.2)' : 'rgba(0,0,0,0.08)')
26
- : (isDark ? 'rgba(100,120,255,0.06)' : 'rgba(0,0,0,0.03)'),
27
- color: isDark ? '#aab' : '#555',
28
- }}
29
- >
30
- Clusters {hiddenClusters.size > 0 ? `(${clusters.length - hiddenClusters.size}/${clusters.length})` : ''}
31
- </button>
32
-
33
- {open && (
34
- <div style={{
35
- position: 'absolute', top: '100%', right: 0, marginTop: '6px',
36
- background: isDark ? 'rgba(10,10,20,0.95)' : 'rgba(255,255,255,0.97)',
37
- border: `1px solid ${isDark ? 'rgba(100,120,255,0.15)' : 'rgba(0,0,0,0.1)'}`,
38
- borderRadius: '8px', padding: '8px', minWidth: '200px',
39
- backdropFilter: 'blur(8px)', zIndex: 100,
40
- boxShadow: isDark ? 'none' : '0 4px 16px rgba(0,0,0,0.08)',
41
- }}>
42
- {[...clusters]
43
- .sort((a, b) => b.nodeCount - a.nodeCount)
44
- .map((c) => (
45
- <label
46
- key={c.id}
47
- style={{
48
- display: 'flex', alignItems: 'center', gap: '8px',
49
- padding: '4px 6px', borderRadius: '4px', cursor: 'pointer',
50
- opacity: hiddenClusters.has(c.id) ? 0.3 : 1,
51
- fontSize: '11px', color: isDark ? '#aab' : '#444',
52
- }}
53
- >
54
- <div style={{
55
- width: '10px', height: '10px', borderRadius: '50%',
56
- background: hiddenClusters.has(c.id) ? '#333' : c.color,
57
- flexShrink: 0,
58
- }} />
59
- <span style={{ flex: 1 }}>{c.label}</span>
60
- <span style={{ color: '#556', fontSize: '10px' }}>{c.nodeCount}</span>
61
- <input
62
- type="checkbox"
63
- checked={!hiddenClusters.has(c.id)}
64
- onChange={() => toggleHiddenCluster(c.id)}
65
- style={{ accentColor: c.color }}
66
- />
67
- </label>
68
- ))}
69
- </div>
70
- )}
71
- </div>
72
- );
73
- }
@@ -1,232 +0,0 @@
1
- // Design Ref: §3 — 별자리 뷰
2
- // Design Ref: §8 — LOD 확장 (universe/constellation/note 3단계)
3
- // 줌아웃(>800) → universe: 별자리 강조, 줌인(<300) → note: 개별 노드
4
-
5
- import { useMemo, useRef } from 'react';
6
- import { useFrame, useThree } from '@react-three/fiber';
7
- import { Html } from '@react-three/drei';
8
- import * as THREE from 'three';
9
- import { useGraphStore } from '../stores/graph-store.js';
10
- import { buildConstellations, type ConstellationData } from '../lib/constellation.js';
11
- import { useConstellationLOD } from '../hooks/useConstellationLOD.js';
12
-
13
- function darkenHex(hex: string, factor: number): string {
14
- const c = hex.replace('#', '');
15
- const r = Math.round(parseInt(c.slice(0, 2), 16) * factor);
16
- const g = Math.round(parseInt(c.slice(2, 4), 16) * factor);
17
- const b = Math.round(parseInt(c.slice(4, 6), 16) * factor);
18
- return `rgb(${r},${g},${b})`;
19
- }
20
-
21
- export function ConstellationView() {
22
- const nodes = useGraphStore((s) => s.nodes);
23
- const clusters = useGraphStore((s) => s.clusters);
24
- const theme = useGraphStore((s) => s.theme);
25
- const isLight = theme === 'light';
26
- const showConstellation = useGraphStore((s) => s.showConstellation);
27
-
28
- if (!showConstellation) return null;
29
- const groupRef = useRef<THREE.Group>(null);
30
- const { constellationOpacity } = useConstellationLOD();
31
- const opacityRef = useRef(0);
32
-
33
- // 별자리 데이터 계산 (노드/클러스터 변경 시에만)
34
- const data: ConstellationData = useMemo(() => {
35
- if (nodes.length === 0 || clusters.length === 0) return { lines: [], labels: [] };
36
- return buildConstellations(nodes, clusters);
37
- }, [nodes, clusters]);
38
-
39
- // 별자리 라인 geometry
40
- const lineGeometries = useMemo(() => {
41
- const geoMap = new Map<number, THREE.BufferGeometry>();
42
-
43
- // 클러스터별로 라인 그룹화
44
- const byCluster = new Map<number, number[]>();
45
- for (const line of data.lines) {
46
- if (!byCluster.has(line.clusterId)) byCluster.set(line.clusterId, []);
47
- const arr = byCluster.get(line.clusterId)!;
48
- arr.push(line.from[0], line.from[1], line.from[2]);
49
- arr.push(line.to[0], line.to[1], line.to[2]);
50
- }
51
-
52
- for (const [cId, positions] of byCluster) {
53
- const geo = new THREE.BufferGeometry();
54
- geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
55
- geoMap.set(cId, geo);
56
- }
57
-
58
- return geoMap;
59
- }, [data]);
60
-
61
- const highlightedNodeIds = useGraphStore((s) => s.highlightedNodeIds);
62
- const hoveredNodeId = useGraphStore((s) => s.hoveredNodeId);
63
- const selectedNodeId = useGraphStore((s) => s.selectedNodeId);
64
- const hasInteraction = highlightedNodeIds.size > 0 || !!hoveredNodeId || !!selectedNodeId;
65
-
66
- // LOD + 상호작용 상태에 따라 별자리 표시
67
- useFrame(() => {
68
- const group = groupRef.current;
69
- if (!group) return;
70
-
71
- // 상호작용 중이면 별자리를 대폭 페이드 (활성 노드에 집중)
72
- let targetOpacity = constellationOpacity;
73
- if (hasInteraction) {
74
- targetOpacity = isLight ? 0.03 : constellationOpacity * 0.15;
75
- }
76
-
77
- opacityRef.current += (targetOpacity - opacityRef.current) * 0.08;
78
- const opacity = opacityRef.current;
79
-
80
- group.visible = opacity > 0.01;
81
-
82
- group.traverse((child) => {
83
- if ((child as THREE.LineSegments).isLineSegments) {
84
- const mat = (child as THREE.LineSegments).material as THREE.LineBasicMaterial;
85
- mat.opacity = isLight ? opacity * 0.6 : opacity * 0.4;
86
- }
87
- });
88
- });
89
-
90
- if (data.lines.length === 0) return null;
91
-
92
- // 클러스터 컬러 맵
93
- const colorMap = new Map(clusters.map(c => [c.id, c.color]));
94
-
95
- return (
96
- <group ref={groupRef}>
97
- {/* 별자리 라인 — 은은한 클러스터 컬러 */}
98
- {[...lineGeometries.entries()].map(([cId, geo]) => (
99
- <lineSegments key={cId} geometry={geo}>
100
- <lineBasicMaterial
101
- color={isLight ? '#b0b8c8' : (colorMap.get(cId) ?? '#6688ff')}
102
- transparent
103
- opacity={isLight ? 0.35 : 0.12}
104
- depthWrite={false}
105
- blending={isLight ? THREE.NormalBlending : THREE.AdditiveBlending}
106
- />
107
- </lineSegments>
108
- ))}
109
-
110
- {/* 별자리 라벨 */}
111
- {data.labels.map((label) => (
112
- <ConstellationLabel
113
- key={label.clusterId}
114
- position={label.position}
115
- text={label.text}
116
- color={label.color}
117
- clusterId={label.clusterId}
118
- opacityRef={opacityRef}
119
- />
120
- ))}
121
- </group>
122
- );
123
- }
124
-
125
- function ConstellationLabel({ position, text, color, clusterId, opacityRef }: {
126
- position: [number, number, number];
127
- text: string;
128
- color: string;
129
- clusterId: number;
130
- opacityRef: React.RefObject<number>;
131
- }) {
132
- const ref = useRef<HTMLDivElement>(null);
133
- const { camera } = useThree();
134
- const highlightedNodeIds = useGraphStore((s) => s.highlightedNodeIds);
135
- const nodes = useGraphStore((s) => s.nodes);
136
- const themeVal = useGraphStore((s) => s.theme);
137
- const isLightLabel = themeVal === 'light';
138
-
139
- const selectedNodeId = useGraphStore((s) => s.selectedNodeId);
140
-
141
- // 이 클러스터가 활성 상태인지: 하이라이트 중이거나, 선택된 노드가 이 클러스터에 속함
142
- const isActiveCluster =
143
- (highlightedNodeIds.size > 0 && nodes.some(n => n.clusterId === clusterId && highlightedNodeIds.has(n.id))) ||
144
- (selectedNodeId && nodes.some(n => n.id === selectedNodeId && n.clusterId === clusterId));
145
-
146
- useFrame(() => {
147
- if (ref.current) {
148
- // 활성 클러스터 라벨은 줌인해도 항상 보임
149
- const opacity = isActiveCluster ? 1 : (opacityRef.current ?? 0);
150
- ref.current.style.opacity = String(opacity);
151
- }
152
- });
153
-
154
- const handleClick = () => {
155
- const state = useGraphStore.getState();
156
- const clusterNodeIds = state.nodes
157
- .filter(n => n.clusterId === clusterId)
158
- .map(n => n.id);
159
-
160
- // 이미 이 클러스터가 하이라이트 중이면 해제 (토글)
161
- const alreadyActive = clusterNodeIds.length > 0 &&
162
- clusterNodeIds.every(id => state.highlightedNodeIds.has(id));
163
-
164
- if (alreadyActive) {
165
- state.setHighlightedNodes([]);
166
- return;
167
- }
168
-
169
- state.setHighlightedNodes(clusterNodeIds);
170
-
171
- // OrbitControls target을 별자리 중심으로 이동
172
- const controls = (window as any).__sv_controls?.current;
173
- if (controls) {
174
- const target = new THREE.Vector3(...position);
175
- const startTarget = controls.target.clone();
176
- const startPos = controls.object.position.clone();
177
- const dir = startPos.clone().sub(target).normalize();
178
- const endPos = target.clone().add(dir.multiplyScalar(350));
179
-
180
- let t = 0;
181
- function animate() {
182
- t += 0.025;
183
- if (t > 1) t = 1;
184
- const ease = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
185
-
186
- controls.target.lerpVectors(startTarget, target, ease);
187
- controls.object.position.lerpVectors(startPos, endPos, ease);
188
- controls.update();
189
-
190
- if (t < 1) requestAnimationFrame(animate);
191
- }
192
- requestAnimationFrame(animate);
193
- }
194
- };
195
-
196
- return (
197
- <Html position={position} center>
198
- <div
199
- ref={ref}
200
- onClick={handleClick}
201
- style={{
202
- fontSize: isLightLabel ? '13px' : '14px',
203
- fontWeight: isLightLabel ? 800 : 700,
204
- color: isLightLabel ? darkenHex(color, 0.5) : color,
205
- textShadow: isLightLabel
206
- ? '1px 1px 0 rgba(255,255,255,0.9), -1px -1px 0 rgba(255,255,255,0.9), 1px -1px 0 rgba(255,255,255,0.9), -1px 1px 0 rgba(255,255,255,0.9)'
207
- : `0 0 12px ${color}, 0 0 24px ${color}40`,
208
- letterSpacing: '1.5px',
209
- textTransform: 'uppercase',
210
- whiteSpace: 'nowrap',
211
- opacity: 0,
212
- transition: 'none',
213
- cursor: 'pointer',
214
- userSelect: 'none',
215
- }}
216
- onMouseEnter={(e) => {
217
- const darkColor = isLightLabel ? darkenHex(color, 0.3) : color;
218
- (e.target as HTMLElement).style.textShadow = isLightLabel
219
- ? `0 0 4px ${darkColor}, 1px 1px 0 rgba(255,255,255,0.9), -1px -1px 0 rgba(255,255,255,0.9)`
220
- : `0 0 20px ${color}, 0 0 40px ${color}`;
221
- }}
222
- onMouseLeave={(e) => {
223
- (e.target as HTMLElement).style.textShadow = isLightLabel
224
- ? '1px 1px 0 rgba(255,255,255,0.9), -1px -1px 0 rgba(255,255,255,0.9), 1px -1px 0 rgba(255,255,255,0.9), -1px 1px 0 rgba(255,255,255,0.9)'
225
- : `0 0 12px ${color}, 0 0 24px ${color}40`;
226
- }}
227
- >
228
- {text}
229
- </div>
230
- </Html>
231
- );
232
- }