stellavault 0.2.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 (390) hide show
  1. package/package.json +1 -1
  2. package/packages/core/dist/api/dashboard.d.ts +3 -0
  3. package/packages/core/{src/api/dashboard.ts → dist/api/dashboard.js} +8 -11
  4. package/packages/core/dist/api/graph-data.d.ts +11 -0
  5. package/packages/core/dist/api/graph-data.js +255 -0
  6. package/packages/core/dist/api/pwa.d.ts +3 -0
  7. package/packages/core/{src/api/pwa.ts → dist/api/pwa.js} +27 -32
  8. package/packages/core/dist/api/server.d.ts +16 -0
  9. package/packages/core/dist/api/server.js +647 -0
  10. package/packages/core/dist/capture/voice.d.ts +24 -0
  11. package/packages/core/dist/capture/voice.js +135 -0
  12. package/packages/core/{src/cloud/index.ts → dist/cloud/index.d.ts} +1 -0
  13. package/packages/core/dist/cloud/index.js +2 -0
  14. package/packages/core/dist/cloud/sync.d.ts +29 -0
  15. package/packages/core/dist/cloud/sync.js +137 -0
  16. package/packages/core/dist/config.d.ts +27 -0
  17. package/packages/core/dist/config.js +55 -0
  18. package/packages/core/dist/federation/credits.d.ts +26 -0
  19. package/packages/core/dist/federation/credits.js +56 -0
  20. package/packages/core/dist/federation/identity.d.ts +14 -0
  21. package/packages/core/dist/federation/identity.js +74 -0
  22. package/packages/core/{src/federation/index.ts → dist/federation/index.d.ts} +1 -2
  23. package/packages/core/dist/federation/index.js +5 -0
  24. package/packages/core/dist/federation/node.d.ts +31 -0
  25. package/packages/core/dist/federation/node.js +216 -0
  26. package/packages/core/dist/federation/privacy.d.ts +8 -0
  27. package/packages/core/dist/federation/privacy.js +40 -0
  28. package/packages/core/dist/federation/reputation.d.ts +37 -0
  29. package/packages/core/dist/federation/reputation.js +139 -0
  30. package/packages/core/dist/federation/search.d.ts +19 -0
  31. package/packages/core/dist/federation/search.js +101 -0
  32. package/packages/core/dist/federation/sharing.d.ts +72 -0
  33. package/packages/core/dist/federation/sharing.js +246 -0
  34. package/packages/core/dist/federation/trust.d.ts +15 -0
  35. package/packages/core/dist/federation/trust.js +60 -0
  36. package/packages/core/dist/federation/types.d.ts +40 -0
  37. package/packages/core/dist/federation/types.js +3 -0
  38. package/packages/core/dist/i18n/index.d.ts +6 -0
  39. package/packages/core/dist/i18n/index.js +81 -0
  40. package/packages/core/{src/index.ts → dist/index.d.ts} +46 -65
  41. package/packages/core/dist/index.js +69 -0
  42. package/packages/core/dist/indexer/chunker.d.ts +14 -0
  43. package/packages/core/dist/indexer/chunker.js +148 -0
  44. package/packages/core/dist/indexer/embedder.d.ts +8 -0
  45. package/packages/core/dist/indexer/embedder.js +3 -0
  46. package/packages/core/dist/indexer/index.d.ts +28 -0
  47. package/packages/core/dist/indexer/index.js +74 -0
  48. package/packages/core/dist/indexer/local-embedder.d.ts +3 -0
  49. package/packages/core/dist/indexer/local-embedder.js +29 -0
  50. package/packages/core/dist/indexer/scanner.d.ts +11 -0
  51. package/packages/core/dist/indexer/scanner.js +137 -0
  52. package/packages/core/dist/indexer/watcher.d.ts +19 -0
  53. package/packages/core/dist/indexer/watcher.js +49 -0
  54. package/packages/core/dist/intelligence/contradiction-detector.d.ts +20 -0
  55. package/packages/core/dist/intelligence/contradiction-detector.js +115 -0
  56. package/packages/core/dist/intelligence/decay-engine.d.ts +27 -0
  57. package/packages/core/dist/intelligence/decay-engine.js +190 -0
  58. package/packages/core/dist/intelligence/duplicate-detector.d.ts +20 -0
  59. package/packages/core/dist/intelligence/duplicate-detector.js +55 -0
  60. package/packages/core/dist/intelligence/fsrs.d.ts +43 -0
  61. package/packages/core/dist/intelligence/fsrs.js +70 -0
  62. package/packages/core/dist/intelligence/gap-detector.d.ts +25 -0
  63. package/packages/core/dist/intelligence/gap-detector.js +78 -0
  64. package/packages/core/dist/intelligence/learning-path.d.ts +31 -0
  65. package/packages/core/dist/intelligence/learning-path.js +53 -0
  66. package/packages/core/dist/intelligence/notifications.d.ts +31 -0
  67. package/packages/core/dist/intelligence/notifications.js +65 -0
  68. package/packages/core/dist/intelligence/predictive-gaps.d.ts +14 -0
  69. package/packages/core/dist/intelligence/predictive-gaps.js +74 -0
  70. package/packages/core/dist/intelligence/semantic-versioning.d.ts +37 -0
  71. package/packages/core/dist/intelligence/semantic-versioning.js +68 -0
  72. package/packages/core/dist/intelligence/types.d.ts +28 -0
  73. package/packages/core/dist/intelligence/types.js +3 -0
  74. package/packages/core/dist/mcp/custom-tools.d.ts +29 -0
  75. package/packages/core/dist/mcp/custom-tools.js +70 -0
  76. package/packages/core/{src/mcp/index.ts → dist/mcp/index.d.ts} +1 -0
  77. package/packages/core/dist/mcp/index.js +2 -0
  78. package/packages/core/dist/mcp/server.d.ts +49 -0
  79. package/packages/core/dist/mcp/server.js +133 -0
  80. package/packages/core/dist/mcp/tools/agentic-graph.d.ts +87 -0
  81. package/packages/core/dist/mcp/tools/agentic-graph.js +88 -0
  82. package/packages/core/dist/mcp/tools/brief.d.ts +31 -0
  83. package/packages/core/dist/mcp/tools/brief.js +39 -0
  84. package/packages/core/dist/mcp/tools/decay.d.ts +33 -0
  85. package/packages/core/dist/mcp/tools/decay.js +32 -0
  86. package/packages/core/dist/mcp/tools/decision-journal.d.ts +78 -0
  87. package/packages/core/dist/mcp/tools/decision-journal.js +79 -0
  88. package/packages/core/dist/mcp/tools/export.d.ts +29 -0
  89. package/packages/core/dist/mcp/tools/export.js +60 -0
  90. package/packages/core/dist/mcp/tools/federated-search.d.ts +29 -0
  91. package/packages/core/dist/mcp/tools/federated-search.js +36 -0
  92. package/packages/core/dist/mcp/tools/generate-claude-md.d.ts +35 -0
  93. package/packages/core/dist/mcp/tools/generate-claude-md.js +107 -0
  94. package/packages/core/dist/mcp/tools/get-document.d.ts +35 -0
  95. package/packages/core/dist/mcp/tools/get-document.js +25 -0
  96. package/packages/core/dist/mcp/tools/get-related.d.ts +32 -0
  97. package/packages/core/dist/mcp/tools/get-related.js +33 -0
  98. package/packages/core/dist/mcp/tools/learning-path.d.ts +23 -0
  99. package/packages/core/dist/mcp/tools/learning-path.js +45 -0
  100. package/packages/core/dist/mcp/tools/list-topics.d.ts +15 -0
  101. package/packages/core/dist/mcp/tools/list-topics.js +18 -0
  102. package/packages/core/dist/mcp/tools/search.d.ts +39 -0
  103. package/packages/core/dist/mcp/tools/search.js +29 -0
  104. package/packages/core/dist/mcp/tools/snapshot.d.ts +47 -0
  105. package/packages/core/dist/mcp/tools/snapshot.js +84 -0
  106. package/packages/core/dist/multi-vault/index.d.ts +26 -0
  107. package/packages/core/dist/multi-vault/index.js +80 -0
  108. package/packages/core/dist/pack/creator.d.ts +21 -0
  109. package/packages/core/dist/pack/creator.js +105 -0
  110. package/packages/core/dist/pack/exporter.d.ts +4 -0
  111. package/packages/core/dist/pack/exporter.js +18 -0
  112. package/packages/core/dist/pack/importer.d.ts +10 -0
  113. package/packages/core/dist/pack/importer.js +55 -0
  114. package/packages/core/{src/pack/index.ts → dist/pack/index.d.ts} +1 -0
  115. package/packages/core/dist/pack/index.js +5 -0
  116. package/packages/core/dist/pack/marketplace.d.ts +14 -0
  117. package/packages/core/dist/pack/marketplace.js +90 -0
  118. package/packages/core/dist/pack/pii-masker.d.ts +7 -0
  119. package/packages/core/dist/pack/pii-masker.js +29 -0
  120. package/packages/core/dist/pack/types.d.ts +36 -0
  121. package/packages/core/dist/pack/types.js +3 -0
  122. package/packages/core/dist/plugins/index.d.ts +35 -0
  123. package/packages/core/dist/plugins/index.js +57 -0
  124. package/packages/core/dist/plugins/webhooks.d.ts +30 -0
  125. package/packages/core/dist/plugins/webhooks.js +79 -0
  126. package/packages/core/dist/search/bm25.d.ts +4 -0
  127. package/packages/core/dist/search/bm25.js +10 -0
  128. package/packages/core/dist/search/index.d.ts +13 -0
  129. package/packages/core/dist/search/index.js +63 -0
  130. package/packages/core/dist/search/rrf.d.ts +7 -0
  131. package/packages/core/dist/search/rrf.js +21 -0
  132. package/packages/core/dist/search/semantic.d.ts +5 -0
  133. package/packages/core/dist/search/semantic.js +6 -0
  134. package/packages/core/{src/store/index.ts → dist/store/index.d.ts} +1 -0
  135. package/packages/core/dist/store/index.js +2 -0
  136. package/packages/core/dist/store/sqlite-vec.d.ts +6 -0
  137. package/packages/core/dist/store/sqlite-vec.js +251 -0
  138. package/packages/core/dist/store/types.d.ts +20 -0
  139. package/packages/core/dist/store/types.js +3 -0
  140. package/packages/core/dist/team/index.d.ts +25 -0
  141. package/packages/core/dist/team/index.js +97 -0
  142. package/packages/core/dist/types/chunk.d.ts +23 -0
  143. package/packages/core/dist/types/chunk.js +3 -0
  144. package/packages/core/dist/types/document.d.ts +23 -0
  145. package/packages/core/dist/types/document.js +3 -0
  146. package/packages/core/dist/types/graph.d.ts +39 -0
  147. package/packages/core/dist/types/graph.js +3 -0
  148. package/packages/core/dist/types/index.d.ts +5 -0
  149. package/packages/core/dist/types/index.js +2 -0
  150. package/packages/core/dist/types/search.d.ts +39 -0
  151. package/packages/core/dist/types/search.js +3 -0
  152. package/packages/core/dist/utils/retry.d.ts +25 -0
  153. package/packages/core/dist/utils/retry.js +59 -0
  154. package/.github/workflows/pages.yml +0 -37
  155. package/memory/MEMORY.md +0 -25
  156. package/packages/cli/dist/commands/brief-cmd.d.ts.map +0 -1
  157. package/packages/cli/dist/commands/brief-cmd.js.map +0 -1
  158. package/packages/cli/dist/commands/capture-cmd.d.ts.map +0 -1
  159. package/packages/cli/dist/commands/capture-cmd.js.map +0 -1
  160. package/packages/cli/dist/commands/card-cmd.d.ts.map +0 -1
  161. package/packages/cli/dist/commands/card-cmd.js.map +0 -1
  162. package/packages/cli/dist/commands/clip-cmd.d.ts.map +0 -1
  163. package/packages/cli/dist/commands/clip-cmd.js.map +0 -1
  164. package/packages/cli/dist/commands/cloud-cmd.d.ts.map +0 -1
  165. package/packages/cli/dist/commands/cloud-cmd.js.map +0 -1
  166. package/packages/cli/dist/commands/contradictions-cmd.d.ts.map +0 -1
  167. package/packages/cli/dist/commands/contradictions-cmd.js.map +0 -1
  168. package/packages/cli/dist/commands/decay-cmd.d.ts.map +0 -1
  169. package/packages/cli/dist/commands/decay-cmd.js.map +0 -1
  170. package/packages/cli/dist/commands/digest-cmd.d.ts.map +0 -1
  171. package/packages/cli/dist/commands/digest-cmd.js.map +0 -1
  172. package/packages/cli/dist/commands/duplicates-cmd.d.ts.map +0 -1
  173. package/packages/cli/dist/commands/duplicates-cmd.js.map +0 -1
  174. package/packages/cli/dist/commands/federate-cmd.d.ts.map +0 -1
  175. package/packages/cli/dist/commands/federate-cmd.js.map +0 -1
  176. package/packages/cli/dist/commands/gaps-cmd.d.ts.map +0 -1
  177. package/packages/cli/dist/commands/gaps-cmd.js.map +0 -1
  178. package/packages/cli/dist/commands/graph-cmd.d.ts.map +0 -1
  179. package/packages/cli/dist/commands/graph-cmd.js.map +0 -1
  180. package/packages/cli/dist/commands/index-cmd.d.ts.map +0 -1
  181. package/packages/cli/dist/commands/index-cmd.js.map +0 -1
  182. package/packages/cli/dist/commands/init-cmd.d.ts.map +0 -1
  183. package/packages/cli/dist/commands/init-cmd.js.map +0 -1
  184. package/packages/cli/dist/commands/learn-cmd.d.ts.map +0 -1
  185. package/packages/cli/dist/commands/learn-cmd.js.map +0 -1
  186. package/packages/cli/dist/commands/pack-cmd.d.ts.map +0 -1
  187. package/packages/cli/dist/commands/pack-cmd.js.map +0 -1
  188. package/packages/cli/dist/commands/review-cmd.d.ts.map +0 -1
  189. package/packages/cli/dist/commands/review-cmd.js.map +0 -1
  190. package/packages/cli/dist/commands/search-cmd.d.ts.map +0 -1
  191. package/packages/cli/dist/commands/search-cmd.js.map +0 -1
  192. package/packages/cli/dist/commands/serve-cmd.d.ts.map +0 -1
  193. package/packages/cli/dist/commands/serve-cmd.js.map +0 -1
  194. package/packages/cli/dist/commands/status-cmd.d.ts.map +0 -1
  195. package/packages/cli/dist/commands/status-cmd.js.map +0 -1
  196. package/packages/cli/dist/commands/sync-cmd.d.ts.map +0 -1
  197. package/packages/cli/dist/commands/sync-cmd.js.map +0 -1
  198. package/packages/cli/dist/commands/vault-cmd.d.ts.map +0 -1
  199. package/packages/cli/dist/commands/vault-cmd.js.map +0 -1
  200. package/packages/cli/dist/index.d.ts.map +0 -1
  201. package/packages/cli/dist/index.js.map +0 -1
  202. package/packages/cli/src/commands/brief-cmd.ts +0 -87
  203. package/packages/cli/src/commands/capture-cmd.ts +0 -34
  204. package/packages/cli/src/commands/card-cmd.ts +0 -29
  205. package/packages/cli/src/commands/clip-cmd.ts +0 -172
  206. package/packages/cli/src/commands/cloud-cmd.ts +0 -75
  207. package/packages/cli/src/commands/contradictions-cmd.ts +0 -41
  208. package/packages/cli/src/commands/decay-cmd.ts +0 -57
  209. package/packages/cli/src/commands/digest-cmd.ts +0 -89
  210. package/packages/cli/src/commands/duplicates-cmd.ts +0 -38
  211. package/packages/cli/src/commands/federate-cmd.ts +0 -256
  212. package/packages/cli/src/commands/gaps-cmd.ts +0 -40
  213. package/packages/cli/src/commands/graph-cmd.ts +0 -88
  214. package/packages/cli/src/commands/index-cmd.ts +0 -65
  215. package/packages/cli/src/commands/init-cmd.ts +0 -145
  216. package/packages/cli/src/commands/learn-cmd.ts +0 -56
  217. package/packages/cli/src/commands/pack-cmd.ts +0 -121
  218. package/packages/cli/src/commands/review-cmd.ts +0 -125
  219. package/packages/cli/src/commands/search-cmd.ts +0 -45
  220. package/packages/cli/src/commands/serve-cmd.ts +0 -17
  221. package/packages/cli/src/commands/status-cmd.ts +0 -37
  222. package/packages/cli/src/commands/sync-cmd.ts +0 -68
  223. package/packages/cli/src/commands/vault-cmd.ts +0 -64
  224. package/packages/cli/src/index.ts +0 -187
  225. package/packages/core/src/api/graph-data.ts +0 -286
  226. package/packages/core/src/api/server.ts +0 -660
  227. package/packages/core/src/capture/voice.ts +0 -168
  228. package/packages/core/src/cloud/sync.ts +0 -167
  229. package/packages/core/src/config.ts +0 -82
  230. package/packages/core/src/federation/credits.ts +0 -80
  231. package/packages/core/src/federation/hyperswarm.d.ts +0 -19
  232. package/packages/core/src/federation/identity.ts +0 -90
  233. package/packages/core/src/federation/node.ts +0 -235
  234. package/packages/core/src/federation/privacy.ts +0 -52
  235. package/packages/core/src/federation/reputation.ts +0 -202
  236. package/packages/core/src/federation/search.ts +0 -129
  237. package/packages/core/src/federation/sharing.ts +0 -315
  238. package/packages/core/src/federation/trust.ts +0 -76
  239. package/packages/core/src/federation/types.ts +0 -25
  240. package/packages/core/src/i18n/index.ts +0 -85
  241. package/packages/core/src/indexer/chunker.ts +0 -180
  242. package/packages/core/src/indexer/embedder.ts +0 -9
  243. package/packages/core/src/indexer/index.ts +0 -113
  244. package/packages/core/src/indexer/local-embedder.ts +0 -35
  245. package/packages/core/src/indexer/scanner.ts +0 -142
  246. package/packages/core/src/indexer/watcher.ts +0 -62
  247. package/packages/core/src/intelligence/contradiction-detector.ts +0 -134
  248. package/packages/core/src/intelligence/decay-engine.ts +0 -229
  249. package/packages/core/src/intelligence/duplicate-detector.ts +0 -71
  250. package/packages/core/src/intelligence/fsrs.ts +0 -79
  251. package/packages/core/src/intelligence/gap-detector.ts +0 -109
  252. package/packages/core/src/intelligence/learning-path.ts +0 -86
  253. package/packages/core/src/intelligence/notifications.ts +0 -106
  254. package/packages/core/src/intelligence/predictive-gaps.ts +0 -94
  255. package/packages/core/src/intelligence/semantic-versioning.ts +0 -97
  256. package/packages/core/src/intelligence/types.ts +0 -28
  257. package/packages/core/src/mcp/custom-tools.ts +0 -97
  258. package/packages/core/src/mcp/server.ts +0 -142
  259. package/packages/core/src/mcp/tools/agentic-graph.ts +0 -96
  260. package/packages/core/src/mcp/tools/brief.ts +0 -49
  261. package/packages/core/src/mcp/tools/decay.ts +0 -40
  262. package/packages/core/src/mcp/tools/decision-journal.ts +0 -95
  263. package/packages/core/src/mcp/tools/export.ts +0 -72
  264. package/packages/core/src/mcp/tools/federated-search.ts +0 -43
  265. package/packages/core/src/mcp/tools/generate-claude-md.ts +0 -130
  266. package/packages/core/src/mcp/tools/get-document.ts +0 -26
  267. package/packages/core/src/mcp/tools/get-related.ts +0 -41
  268. package/packages/core/src/mcp/tools/learning-path.ts +0 -52
  269. package/packages/core/src/mcp/tools/list-topics.ts +0 -20
  270. package/packages/core/src/mcp/tools/search.ts +0 -35
  271. package/packages/core/src/mcp/tools/snapshot.ts +0 -98
  272. package/packages/core/src/multi-vault/index.ts +0 -118
  273. package/packages/core/src/pack/creator.ts +0 -127
  274. package/packages/core/src/pack/exporter.ts +0 -21
  275. package/packages/core/src/pack/importer.ts +0 -82
  276. package/packages/core/src/pack/marketplace.ts +0 -103
  277. package/packages/core/src/pack/pii-masker.ts +0 -38
  278. package/packages/core/src/pack/types.ts +0 -39
  279. package/packages/core/src/plugins/index.ts +0 -100
  280. package/packages/core/src/plugins/webhooks.ts +0 -110
  281. package/packages/core/src/search/bm25.ts +0 -16
  282. package/packages/core/src/search/index.ts +0 -83
  283. package/packages/core/src/search/rrf.ts +0 -31
  284. package/packages/core/src/search/semantic.ts +0 -15
  285. package/packages/core/src/store/sqlite-vec.ts +0 -290
  286. package/packages/core/src/store/types.ts +0 -22
  287. package/packages/core/src/team/index.ts +0 -126
  288. package/packages/core/src/types/chunk.ts +0 -25
  289. package/packages/core/src/types/document.ts +0 -24
  290. package/packages/core/src/types/graph.ts +0 -44
  291. package/packages/core/src/types/index.ts +0 -15
  292. package/packages/core/src/types/search.ts +0 -38
  293. package/packages/core/src/utils/retry.ts +0 -85
  294. package/packages/core/tests/api-card.test.ts +0 -60
  295. package/packages/core/tests/api-routes.test.ts +0 -98
  296. package/packages/core/tests/bm25.test.ts +0 -87
  297. package/packages/core/tests/chunker.test.ts +0 -48
  298. package/packages/core/tests/cluster.test.ts +0 -75
  299. package/packages/core/tests/constellation.test.ts +0 -77
  300. package/packages/core/tests/export-utils.test.ts +0 -97
  301. package/packages/core/tests/fsrs.test.ts +0 -96
  302. package/packages/core/tests/gesture-detector.test.ts +0 -45
  303. package/packages/core/tests/graph-data.test.ts +0 -87
  304. package/packages/core/tests/layout.test.ts +0 -83
  305. package/packages/core/tests/mcp.test.ts +0 -148
  306. package/packages/core/tests/pack.test.ts +0 -127
  307. package/packages/core/tests/pii-masker.test.ts +0 -42
  308. package/packages/core/tests/profile-card.test.ts +0 -62
  309. package/packages/core/tests/rrf.test.ts +0 -29
  310. package/packages/core/tests/search-integration.test.ts +0 -139
  311. package/packages/core/tests/store.test.ts +0 -80
  312. package/packages/graph/click-result.png +0 -0
  313. package/packages/graph/dist/assets/camera_utils-BMxqtvoZ.js +0 -1
  314. package/packages/graph/dist/assets/hands-DXA01_mx.js +0 -18
  315. package/packages/graph/dist/assets/index-DMEe2diW.js +0 -4192
  316. package/packages/graph/dist/assets/layout.worker-DbKCEFTz.js +0 -1
  317. package/packages/graph/dist/index.html +0 -17
  318. package/packages/graph/index.html +0 -17
  319. package/packages/graph/package.json +0 -32
  320. package/packages/graph/src/App.tsx +0 -7
  321. package/packages/graph/src/api/client.ts +0 -39
  322. package/packages/graph/src/components/ClusterFilter.tsx +0 -73
  323. package/packages/graph/src/components/ConstellationView.tsx +0 -232
  324. package/packages/graph/src/components/ExportPanel.tsx +0 -177
  325. package/packages/graph/src/components/Graph3D.tsx +0 -230
  326. package/packages/graph/src/components/GraphEdges.tsx +0 -100
  327. package/packages/graph/src/components/GraphNodes.tsx +0 -386
  328. package/packages/graph/src/components/HealthDashboard.tsx +0 -173
  329. package/packages/graph/src/components/Layout.tsx +0 -214
  330. package/packages/graph/src/components/MotionOverlay.tsx +0 -81
  331. package/packages/graph/src/components/MotionToggle.tsx +0 -33
  332. package/packages/graph/src/components/MultiverseView.tsx +0 -286
  333. package/packages/graph/src/components/NodeDetail.tsx +0 -232
  334. package/packages/graph/src/components/PulseParticle.tsx +0 -232
  335. package/packages/graph/src/components/SearchBar.tsx +0 -107
  336. package/packages/graph/src/components/StarField.tsx +0 -197
  337. package/packages/graph/src/components/StatusBar.tsx +0 -53
  338. package/packages/graph/src/components/Timeline.tsx +0 -148
  339. package/packages/graph/src/components/ToolsPanel.tsx +0 -512
  340. package/packages/graph/src/components/Tooltip.tsx +0 -100
  341. package/packages/graph/src/components/TypeFilter.tsx +0 -131
  342. package/packages/graph/src/embed/EmbedGraph.tsx +0 -144
  343. package/packages/graph/src/hooks/useConstellationLOD.ts +0 -76
  344. package/packages/graph/src/hooks/useDecay.ts +0 -37
  345. package/packages/graph/src/hooks/useExport.ts +0 -165
  346. package/packages/graph/src/hooks/useGraph.ts +0 -69
  347. package/packages/graph/src/hooks/useKeyboardNav.ts +0 -122
  348. package/packages/graph/src/hooks/useLayout.ts +0 -45
  349. package/packages/graph/src/hooks/useMotion.ts +0 -120
  350. package/packages/graph/src/hooks/usePulse.ts +0 -58
  351. package/packages/graph/src/hooks/useSearch.ts +0 -71
  352. package/packages/graph/src/lib/constellation.ts +0 -107
  353. package/packages/graph/src/lib/export-utils.ts +0 -48
  354. package/packages/graph/src/lib/gesture-detector.ts +0 -123
  355. package/packages/graph/src/lib/layout.worker.ts +0 -153
  356. package/packages/graph/src/lib/motion-controller.ts +0 -83
  357. package/packages/graph/src/lib/profile-card.ts +0 -122
  358. package/packages/graph/src/main.tsx +0 -4
  359. package/packages/graph/src/stores/graph-store.ts +0 -155
  360. package/packages/graph/success.png +0 -0
  361. package/packages/graph/test-click.mjs +0 -49
  362. package/packages/graph/test-explore.mjs +0 -102
  363. package/packages/graph/test-final.mjs +0 -61
  364. package/packages/graph/test-graph.mjs +0 -139
  365. package/packages/graph/test-hover.mjs +0 -48
  366. package/packages/graph/test-pulse.mjs +0 -68
  367. package/packages/graph/test-screenshot.mjs +0 -56
  368. package/packages/graph/test-v2.mjs +0 -97
  369. package/packages/graph/tsconfig.tsbuildinfo +0 -1
  370. package/packages/graph/vite.config.ts +0 -15
  371. package/packages/sync/.env.example +0 -11
  372. package/packages/sync/.sync-state.json +0 -317
  373. package/packages/sync/.upload-state.json +0 -1009
  374. package/packages/sync/create-stella-network-notion.mjs +0 -151
  375. package/packages/sync/create-stellavault-project-notion.mjs +0 -322
  376. package/packages/sync/logs/sync-2026-03-28.log +0 -6
  377. package/packages/sync/logs/sync-2026-03-29.log +0 -12
  378. package/packages/sync/logs/sync-2026-03-30.log +0 -6
  379. package/packages/sync/logs/sync-2026-03-31.log +0 -6
  380. package/packages/sync/logs/sync-2026-04-01.log +0 -6
  381. package/packages/sync/logs/sync-2026-04-02.log +0 -6
  382. package/packages/sync/package-lock.json +0 -373
  383. package/packages/sync/package.json +0 -16
  384. package/packages/sync/run-sync.bat +0 -18
  385. package/packages/sync/run-sync.mjs +0 -46
  386. package/packages/sync/setup-scheduler.mjs +0 -119
  387. package/packages/sync/structured-sync.mjs +0 -187
  388. package/packages/sync/sync-to-obsidian.mjs +0 -264
  389. package/packages/sync/upload-pdca-to-notion.mjs +0 -495
  390. package/tsconfig.base.json +0 -18
@@ -0,0 +1,647 @@
1
+ // Design Ref: §4.1 — REST API (core/api/)
2
+ // Design Ref: §7 — Security: localhost only, CORS restricted
3
+ import express from 'express';
4
+ import cors from 'cors';
5
+ import { buildGraphData } from './graph-data.js';
6
+ import { detectDuplicates } from '../intelligence/duplicate-detector.js';
7
+ import { detectKnowledgeGaps } from '../intelligence/gap-detector.js';
8
+ export function createApiServer(options) {
9
+ const { store, searchEngine, port = 3333, vaultName = '', vaultPath = '', decayEngine } = options;
10
+ const app = express();
11
+ app.use(cors({ origin: ['http://localhost:5173', 'http://127.0.0.1:5173'] }));
12
+ app.use(express.json());
13
+ // GET /api/graph?mode=semantic|folder — 전체 그래프 데이터
14
+ const graphCaches = new Map();
15
+ app.get('/api/graph', async (req, res) => {
16
+ try {
17
+ const mode = req.query.mode === 'folder' ? 'folder' : 'semantic';
18
+ if (!graphCaches.has(mode)) {
19
+ const data = await buildGraphData(store, { mode });
20
+ graphCaches.set(mode, { data, generatedAt: new Date().toISOString() });
21
+ }
22
+ const cached = graphCaches.get(mode);
23
+ res.json({ data: cached.data, generatedAt: cached.generatedAt, mode });
24
+ }
25
+ catch (err) {
26
+ console.error(err);
27
+ res.status(500).json({ error: 'Internal server error' });
28
+ }
29
+ });
30
+ // GET /api/graph/refresh?mode= — 캐시 무효화 + 재생성
31
+ app.get('/api/graph/refresh', async (req, res) => {
32
+ try {
33
+ const mode = req.query.mode === 'folder' ? 'folder' : 'semantic';
34
+ const data = await buildGraphData(store, { mode });
35
+ graphCaches.set(mode, { data, generatedAt: new Date().toISOString() });
36
+ const cached = graphCaches.get(mode);
37
+ res.json({ data: cached.data, generatedAt: cached.generatedAt, mode });
38
+ }
39
+ catch (err) {
40
+ console.error(err);
41
+ res.status(500).json({ error: 'Internal server error' });
42
+ }
43
+ });
44
+ // GET /api/search?q=&limit=
45
+ app.get('/api/search', async (req, res) => {
46
+ try {
47
+ const query = String(req.query.q || '');
48
+ const limit = parseInt(String(req.query.limit || '10'), 10);
49
+ if (!query) {
50
+ res.json({ results: [], query: '' });
51
+ return;
52
+ }
53
+ const results = await searchEngine.search({ query, limit });
54
+ // 검색 결과 문서에 대해 접근 이벤트 기록 (감쇠 리셋)
55
+ if (decayEngine) {
56
+ const now = new Date().toISOString();
57
+ for (const r of results) {
58
+ decayEngine.recordAccess({ documentId: r.document.id, type: 'search', timestamp: now }).catch(() => { });
59
+ }
60
+ }
61
+ res.json({
62
+ results: results.map(r => ({
63
+ documentId: r.document.id,
64
+ title: r.document.title,
65
+ score: Math.round(r.score * 1000) / 1000,
66
+ highlights: r.highlights,
67
+ })),
68
+ query,
69
+ });
70
+ }
71
+ catch (err) {
72
+ console.error(err);
73
+ res.status(500).json({ error: 'Internal server error' });
74
+ }
75
+ });
76
+ // GET /api/document/:id
77
+ app.get('/api/document/:id', async (req, res) => {
78
+ try {
79
+ const doc = await store.getDocument(req.params.id);
80
+ if (!doc) {
81
+ res.status(404).json({ error: 'Not found' });
82
+ return;
83
+ }
84
+ // 접근 이벤트 기록 (감쇠 리셋)
85
+ if (decayEngine) {
86
+ decayEngine.recordAccess({ documentId: doc.id, type: 'view', timestamp: new Date().toISOString() }).catch(() => { });
87
+ }
88
+ // 관련 문서 (제목 기반 검색)
89
+ const related = await searchEngine.search({
90
+ query: doc.title,
91
+ limit: 6,
92
+ });
93
+ res.json({
94
+ id: doc.id,
95
+ title: doc.title,
96
+ filePath: doc.filePath,
97
+ content: doc.content,
98
+ tags: doc.tags,
99
+ lastModified: doc.lastModified,
100
+ related: related
101
+ .filter(r => r.document.id !== doc.id)
102
+ .slice(0, 5)
103
+ .map(r => ({ id: r.document.id, title: r.document.title, score: r.score })),
104
+ });
105
+ }
106
+ catch (err) {
107
+ console.error(err);
108
+ res.status(500).json({ error: 'Internal server error' });
109
+ }
110
+ });
111
+ // GET /api/profile-card → SVG
112
+ app.get('/api/profile-card', async (_req, res) => {
113
+ try {
114
+ const mode = _req.query.mode === 'folder' ? 'folder' : 'semantic';
115
+ if (!graphCaches.has(mode)) {
116
+ const data = await buildGraphData(store, { mode });
117
+ graphCaches.set(mode, { data, generatedAt: new Date().toISOString() });
118
+ }
119
+ const graphData = graphCaches.get(mode).data;
120
+ const topics = await store.getTopics();
121
+ // 동적 import (graph 패키지의 profile-card)
122
+ // 여기서는 간단히 SVG를 직접 생성
123
+ const stats = await store.getStats();
124
+ const top6 = graphData.clusters
125
+ .sort((a, b) => b.nodeCount - a.nodeCount)
126
+ .slice(0, 6);
127
+ const maxCount = Math.max(1, ...top6.map((c) => c.nodeCount));
128
+ const W = 800, H = 420;
129
+ const radarCx = 200, radarCy = 220, radarR = 100;
130
+ const radarPoints = top6.map((c, i) => {
131
+ const angle = (Math.PI * 2 * i) / top6.length - Math.PI / 2;
132
+ const r = radarR * (c.nodeCount / maxCount);
133
+ return {
134
+ x: radarCx + r * Math.cos(angle),
135
+ y: radarCy + r * Math.sin(angle),
136
+ lx: radarCx + (radarR + 20) * Math.cos(angle),
137
+ ly: radarCy + (radarR + 20) * Math.sin(angle),
138
+ label: c.label.split(',')[0].trim().slice(0, 12),
139
+ color: c.color,
140
+ };
141
+ });
142
+ const radarPath = radarPoints.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ') + 'Z';
143
+ const gridPaths = [0.33, 0.66, 1].map((s) => top6.map((_, i) => {
144
+ const a = (Math.PI * 2 * i) / top6.length - Math.PI / 2;
145
+ return `${i === 0 ? 'M' : 'L'}${radarCx + radarR * s * Math.cos(a)},${radarCy + radarR * s * Math.sin(a)}`;
146
+ }).join(' ') + 'Z');
147
+ const tags20 = topics.slice(0, 20);
148
+ const maxTag = Math.max(1, ...tags20.map((t) => t.count));
149
+ // HIGH-07: SVG injection 방어 — 모든 특수문자 이스케이프
150
+ const esc = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
151
+ const tagEls = tags20.map((t, i) => {
152
+ const sz = 10 + 14 * (t.count / maxTag);
153
+ const x = 480 + (Math.floor(i / 2) % 5) * 60;
154
+ const y = 140 + (i % 2) * 30 + Math.floor(i / 10) * 70;
155
+ const op = 0.5 + 0.5 * (t.count / maxTag);
156
+ return `<text x="${x}" y="${y}" font-size="${sz}" fill="#88aaff" opacity="${op}" font-family="monospace">#${esc(t.topic)}</text>`;
157
+ }).join('\n ');
158
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
159
+ <defs>
160
+ <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
161
+ <stop offset="0%" stop-color="#0d1028"/><stop offset="100%" stop-color="#050510"/>
162
+ </linearGradient>
163
+ <linearGradient id="rf" x1="0%" y1="0%" x2="100%" y2="100%">
164
+ <stop offset="0%" stop-color="#6366f1" stop-opacity="0.3"/><stop offset="100%" stop-color="#06b6d4" stop-opacity="0.15"/>
165
+ </linearGradient>
166
+ </defs>
167
+ <rect width="${W}" height="${H}" rx="16" fill="url(#bg)"/>
168
+ <rect width="${W}" height="${H}" rx="16" fill="none" stroke="#6366f140"/>
169
+ <text x="30" y="40" font-size="20" font-weight="700" fill="#c0c0f0" font-family="system-ui">🧠 Knowledge Universe</text>
170
+ <text x="30" y="65" font-size="13" fill="#556" font-family="monospace">${stats.documentCount} docs · ${graphData.clusters.length} clusters · ${graphData.edges.length} connections</text>
171
+ <line x1="30" y1="80" x2="${W - 30}" y2="80" stroke="#6366f120"/>
172
+ <text x="${radarCx}" y="105" font-size="11" fill="#667" text-anchor="middle" font-family="system-ui">KNOWLEDGE DISTRIBUTION</text>
173
+ ${gridPaths.map((p) => `<path d="${p}" fill="none" stroke="#6366f115" stroke-width="0.5"/>`).join('\n ')}
174
+ ${radarPoints.map((p) => `<line x1="${radarCx}" y1="${radarCy}" x2="${p.lx}" y2="${p.ly}" stroke="#6366f110" stroke-width="0.5"/>`).join('\n ')}
175
+ <path d="${radarPath}" fill="url(#rf)" stroke="#818cf8" stroke-width="1.5"/>
176
+ ${radarPoints.map((p) => `<circle cx="${p.x}" cy="${p.y}" r="3" fill="${p.color}"/><text x="${p.lx}" y="${p.ly + 4}" font-size="9" fill="#889" text-anchor="middle" font-family="monospace">${esc(p.label)}</text>`).join('\n ')}
177
+ <text x="580" y="105" font-size="11" fill="#667" text-anchor="middle" font-family="system-ui">TOP TOPICS</text>
178
+ <rect x="440" y="115" width="320" height="240" rx="8" fill="#6366f108"/>
179
+ ${tagEls}
180
+ <text x="${W / 2}" y="${H - 15}" font-size="10" fill="#334" text-anchor="middle" font-family="monospace">Generated by Stellavault</text>
181
+ </svg>`;
182
+ res.setHeader('Content-Type', 'image/svg+xml');
183
+ res.send(svg);
184
+ }
185
+ catch (err) {
186
+ console.error(err);
187
+ res.status(500).json({ error: 'Internal server error' });
188
+ }
189
+ });
190
+ // GET /api/stats
191
+ app.get('/api/stats', async (_req, res) => {
192
+ try {
193
+ const stats = await store.getStats();
194
+ res.json({ ...stats, vaultName });
195
+ }
196
+ catch (err) {
197
+ console.error(err);
198
+ res.status(500).json({ error: 'Internal server error' });
199
+ }
200
+ });
201
+ // GET /api/decay — 감쇠 상태 리포트
202
+ app.get('/api/decay', async (_req, res) => {
203
+ if (!decayEngine) {
204
+ res.json({ error: 'Decay engine not initialized' });
205
+ return;
206
+ }
207
+ try {
208
+ const report = await decayEngine.computeAll();
209
+ res.json(report);
210
+ }
211
+ catch (err) {
212
+ console.error(err);
213
+ res.status(500).json({ error: 'Internal server error' });
214
+ }
215
+ });
216
+ // GET /api/duplicates — 중복 노트 탐지
217
+ app.get('/api/duplicates', async (req, res) => {
218
+ try {
219
+ const threshold = parseFloat(String(req.query.threshold ?? '0.88'));
220
+ const pairs = await detectDuplicates(store, threshold, 20);
221
+ res.json({ pairs, count: pairs.length, threshold });
222
+ }
223
+ catch (err) {
224
+ console.error(err);
225
+ res.status(500).json({ error: 'Internal server error' });
226
+ }
227
+ });
228
+ // GET /api/gaps — 지식 갭 탐지
229
+ app.get('/api/gaps', async (_req, res) => {
230
+ try {
231
+ const report = await detectKnowledgeGaps(store);
232
+ res.json(report);
233
+ }
234
+ catch (err) {
235
+ console.error(err);
236
+ res.status(500).json({ error: 'Internal server error' });
237
+ }
238
+ });
239
+ // POST /api/duplicates/merge — 중복 노트 자동 병합
240
+ app.post('/api/duplicates/merge', async (req, res) => {
241
+ try {
242
+ const { docAId, docBId } = req.body;
243
+ if (!docAId || !docBId) {
244
+ res.status(400).json({ error: 'docAId, docBId required' });
245
+ return;
246
+ }
247
+ const docA = await store.getDocument(docAId);
248
+ const docB = await store.getDocument(docBId);
249
+ if (!docA || !docB) {
250
+ res.status(404).json({ error: 'Document not found' });
251
+ return;
252
+ }
253
+ const { readFileSync, writeFileSync, unlinkSync } = await import('node:fs');
254
+ const { join, resolve, relative } = await import('node:path');
255
+ // 긴 노트를 기준으로 유지, 짧은 노트의 고유 내용을 추가
256
+ const [keeper, removed] = docA.content.length >= docB.content.length
257
+ ? [docA, docB] : [docB, docA];
258
+ // HIGH-02: Path Traversal 방어 — vault 외부 접근 차단
259
+ const keeperPath = resolve(join(vaultPath, keeper.filePath));
260
+ const removedPath = resolve(join(vaultPath, removed.filePath));
261
+ const vaultRoot = resolve(vaultPath);
262
+ if (!keeperPath.startsWith(vaultRoot) || !removedPath.startsWith(vaultRoot)) {
263
+ res.status(400).json({ error: 'Invalid file path' });
264
+ return;
265
+ }
266
+ // 병합: keeper 끝에 removed 고유 내용 추가
267
+ const keeperContent = readFileSync(keeperPath, 'utf-8');
268
+ const appendix = `\n\n---\n\n> Merged from: ${removed.title} (${removed.filePath})\n\n${removed.content}`;
269
+ writeFileSync(keeperPath, keeperContent + appendix, 'utf-8');
270
+ // 삭제
271
+ try {
272
+ unlinkSync(removedPath);
273
+ }
274
+ catch { /* 이미 없을 수 있음 */ }
275
+ // DB에서도 삭제
276
+ await store.deleteByDocumentId(removed.id);
277
+ res.json({
278
+ success: true,
279
+ kept: { id: keeper.id, title: keeper.title },
280
+ removed: { id: removed.id, title: removed.title },
281
+ });
282
+ }
283
+ catch (err) {
284
+ console.error(err);
285
+ res.status(500).json({ error: 'Merge failed' });
286
+ }
287
+ });
288
+ // POST /api/gaps/create-bridge — 갭 브릿지 노트 자동 생성
289
+ app.post('/api/gaps/create-bridge', async (req, res) => {
290
+ try {
291
+ const { clusterA, clusterB } = req.body;
292
+ if (!clusterA || !clusterB) {
293
+ res.status(400).json({ error: 'clusterA, clusterB required' });
294
+ return;
295
+ }
296
+ const { writeFileSync, mkdirSync } = await import('node:fs');
297
+ const { join } = await import('node:path');
298
+ const nameA = clusterA.replace(/\s*\(\d+\)$/, '');
299
+ const nameB = clusterB.replace(/\s*\(\d+\)$/, '');
300
+ // 양쪽 클러스터의 대표 노트 검색
301
+ const resultsA = await searchEngine.search({ query: nameA, limit: 3 });
302
+ const resultsB = await searchEngine.search({ query: nameB, limit: 3 });
303
+ const refsA = resultsA.map(r => `- [[${r.document.title}]]: ${r.document.content.slice(0, 100).replace(/\n/g, ' ')}...`).join('\n');
304
+ const refsB = resultsB.map(r => `- [[${r.document.title}]]: ${r.document.content.slice(0, 100).replace(/\n/g, ' ')}...`).join('\n');
305
+ const title = `${nameA} × ${nameB}`;
306
+ const date = new Date().toISOString().slice(0, 10);
307
+ const content = [
308
+ '---',
309
+ `title: "${title}"`,
310
+ `created: ${date}`,
311
+ 'tags: [bridge, auto-generated]',
312
+ '---',
313
+ '',
314
+ `# ${title}`,
315
+ '',
316
+ `> 이 노트는 지식 갭 탐지기에 의해 자동 생성되었습니다.`,
317
+ `> ${nameA}와 ${nameB} 사이의 연결 지식을 정리하세요.`,
318
+ '',
319
+ `## ${nameA} 핵심 노트`,
320
+ '',
321
+ refsA || '- (관련 노트 없음)',
322
+ '',
323
+ `## ${nameB} 핵심 노트`,
324
+ '',
325
+ refsB || '- (관련 노트 없음)',
326
+ '',
327
+ '## 연결 포인트',
328
+ '',
329
+ `${nameA}와 ${nameB}의 관계:`,
330
+ '',
331
+ '- ',
332
+ '',
333
+ '## 메모',
334
+ '',
335
+ '',
336
+ ].join('\n');
337
+ const safeTitle = title.replace(/[<>:"/\\|?*]/g, '').replace(/\s+/g, ' ');
338
+ const { resolve } = await import('node:path');
339
+ const dir = resolve(join(vaultPath, '01_Knowledge'));
340
+ if (!dir.startsWith(resolve(vaultPath))) {
341
+ res.status(400).json({ error: 'Invalid path' });
342
+ return;
343
+ }
344
+ mkdirSync(dir, { recursive: true });
345
+ const filePath = join(dir, `${safeTitle}.md`);
346
+ writeFileSync(filePath, content, 'utf-8');
347
+ res.json({ success: true, title: safeTitle, path: filePath });
348
+ }
349
+ catch (err) {
350
+ console.error(err);
351
+ res.status(500).json({ error: 'Bridge creation failed' });
352
+ }
353
+ });
354
+ // GET /api/health — 종합 건강도 대시보드
355
+ app.get('/api/health', async (_req, res) => {
356
+ try {
357
+ const stats = await store.getStats();
358
+ const docs = await store.getAllDocuments();
359
+ // Decay 요약
360
+ let decaySummary = { totalDocuments: 0, criticalCount: 0, decayingCount: 0, averageR: 1.0, topDecaying: [] };
361
+ if (decayEngine) {
362
+ const report = await decayEngine.computeAll();
363
+ decaySummary = {
364
+ totalDocuments: report.totalDocuments ?? docs.length,
365
+ criticalCount: report.criticalCount ?? 0,
366
+ decayingCount: report.decayingCount ?? 0,
367
+ averageR: report.averageR ?? 1.0,
368
+ topDecaying: (report.topDecaying ?? []).slice(0, 5),
369
+ };
370
+ }
371
+ // Gaps 요약
372
+ let gapSummary = { gapCount: 0, isolatedCount: 0 };
373
+ try {
374
+ const gapReport = await detectKnowledgeGaps(store);
375
+ gapSummary = {
376
+ gapCount: gapReport.gaps?.length ?? 0,
377
+ isolatedCount: gapReport.isolatedNodes?.length ?? 0,
378
+ };
379
+ }
380
+ catch { /* gaps may fail if no embeddings */ }
381
+ // Duplicates 요약
382
+ let dupCount = 0;
383
+ try {
384
+ const pairs = await detectDuplicates(store, 0.88, 50);
385
+ dupCount = pairs.length;
386
+ }
387
+ catch { /* duplicates may fail */ }
388
+ // Source/Type 분포
389
+ const sourceDist = new Map();
390
+ const typeDist = new Map();
391
+ for (const doc of docs) {
392
+ const s = doc.source ?? 'local';
393
+ const t = doc.type ?? 'note';
394
+ sourceDist.set(s, (sourceDist.get(s) ?? 0) + 1);
395
+ typeDist.set(t, (typeDist.get(t) ?? 0) + 1);
396
+ }
397
+ // 시간별 문서 증가 (월별)
398
+ const monthlyGrowth = new Map();
399
+ for (const doc of docs) {
400
+ const month = doc.lastModified?.slice(0, 7) ?? 'unknown';
401
+ monthlyGrowth.set(month, (monthlyGrowth.get(month) ?? 0) + 1);
402
+ }
403
+ res.json({
404
+ stats: { ...stats, vaultName },
405
+ decay: decaySummary,
406
+ gaps: gapSummary,
407
+ duplicates: { count: dupCount },
408
+ distribution: {
409
+ source: Object.fromEntries(sourceDist),
410
+ type: Object.fromEntries(typeDist),
411
+ },
412
+ growth: Object.fromEntries([...monthlyGrowth.entries()].sort((a, b) => a[0].localeCompare(b[0]))),
413
+ });
414
+ }
415
+ catch (err) {
416
+ console.error(err);
417
+ res.status(500).json({ error: 'Internal server error' });
418
+ }
419
+ });
420
+ // GET /api/profile — Knowledge Profile summary (F-A09)
421
+ app.get('/api/profile', async (_req, res) => {
422
+ try {
423
+ const stats = await store.getStats();
424
+ const topics = await store.getTopics();
425
+ const docs = await store.getAllDocuments();
426
+ let decaySummary = { averageR: 1.0, criticalCount: 0, healthScore: 100 };
427
+ if (decayEngine) {
428
+ const report = await decayEngine.computeAll();
429
+ const avgR = report.averageR ?? 1.0;
430
+ decaySummary = {
431
+ averageR: avgR,
432
+ criticalCount: report.criticalCount ?? 0,
433
+ healthScore: Math.round(avgR * 100),
434
+ };
435
+ }
436
+ // Source/Type distribution
437
+ const sourceDist = {};
438
+ const typeDist = {};
439
+ for (const doc of docs) {
440
+ const s = doc.source ?? 'local';
441
+ const t = doc.type ?? 'note';
442
+ sourceDist[s] = (sourceDist[s] ?? 0) + 1;
443
+ typeDist[t] = (typeDist[t] ?? 0) + 1;
444
+ }
445
+ // Activity: docs per month (last 12)
446
+ const monthlyActivity = {};
447
+ for (const doc of docs) {
448
+ const month = doc.lastModified?.slice(0, 7);
449
+ if (month)
450
+ monthlyActivity[month] = (monthlyActivity[month] ?? 0) + 1;
451
+ }
452
+ res.setHeader('Access-Control-Allow-Origin', '*');
453
+ res.json({
454
+ name: vaultName || 'Knowledge Vault',
455
+ stats: {
456
+ documents: stats.documentCount,
457
+ chunks: stats.chunkCount,
458
+ topics: topics.length,
459
+ },
460
+ healthScore: decaySummary.healthScore,
461
+ topTopics: topics.slice(0, 15).map(t => ({ name: t.topic, count: t.count })),
462
+ distribution: { source: sourceDist, type: typeDist },
463
+ activity: Object.fromEntries(Object.entries(monthlyActivity).sort((a, b) => a[0].localeCompare(b[0])).slice(-12)),
464
+ generatedAt: new Date().toISOString(),
465
+ });
466
+ }
467
+ catch (err) {
468
+ console.error(err);
469
+ res.status(500).json({ error: 'Internal server error' });
470
+ }
471
+ });
472
+ // GET /api/embed — 임베드용 경량 그래프 데이터 (F-A08)
473
+ app.get('/api/embed', async (req, res) => {
474
+ try {
475
+ const mode = req.query.mode === 'folder' ? 'folder' : 'semantic';
476
+ const maxNodes = Math.min(parseInt(String(req.query.max ?? '200'), 10), 500);
477
+ if (!graphCaches.has(mode)) {
478
+ const data = await buildGraphData(store, { mode });
479
+ graphCaches.set(mode, { data, generatedAt: new Date().toISOString() });
480
+ }
481
+ const cached = graphCaches.get(mode);
482
+ const { nodes, edges, clusters } = cached.data;
483
+ const connCount = new Map();
484
+ for (const e of edges) {
485
+ connCount.set(e.source, (connCount.get(e.source) ?? 0) + 1);
486
+ connCount.set(e.target, (connCount.get(e.target) ?? 0) + 1);
487
+ }
488
+ const sortedNodes = [...nodes].sort((a, b) => (connCount.get(b.id) ?? 0) - (connCount.get(a.id) ?? 0));
489
+ const selectedNodes = sortedNodes.slice(0, maxNodes);
490
+ const selectedIds = new Set(selectedNodes.map(n => n.id));
491
+ const selectedEdges = edges.filter((e) => selectedIds.has(e.source) && selectedIds.has(e.target));
492
+ const embedNodes = selectedNodes.map((n, i) => {
493
+ const angle = (i / selectedNodes.length) * Math.PI * 2;
494
+ const r = 100 + n.clusterId * 15;
495
+ return {
496
+ id: n.id, label: n.label, clusterId: n.clusterId, size: n.size,
497
+ position: [
498
+ r * Math.cos(angle) + (Math.random() - 0.5) * 60,
499
+ (Math.random() - 0.5) * 200,
500
+ r * Math.sin(angle) + (Math.random() - 0.5) * 60,
501
+ ],
502
+ };
503
+ });
504
+ res.setHeader('Access-Control-Allow-Origin', '*');
505
+ res.json({
506
+ nodes: embedNodes, edges: selectedEdges,
507
+ stats: { nodeCount: embedNodes.length, edgeCount: selectedEdges.length, clusterCount: clusters.length, totalNodes: nodes.length },
508
+ title: vaultName || 'Knowledge Graph',
509
+ });
510
+ }
511
+ catch (err) {
512
+ console.error(err);
513
+ res.status(500).json({ error: 'Internal server error' });
514
+ }
515
+ });
516
+ // Sync 상태 추적
517
+ let syncState = {
518
+ running: false, startedAt: '', completedAt: '', result: '', output: '',
519
+ };
520
+ // POST /api/sync — Notion → Obsidian 동기화 트리거
521
+ app.post('/api/sync', async (_req, res) => {
522
+ if (syncState.running) {
523
+ res.json({ success: false, error: 'Sync already running', state: syncState });
524
+ return;
525
+ }
526
+ try {
527
+ const { spawn } = await import('node:child_process');
528
+ const { resolve } = await import('node:path');
529
+ const syncScript = resolve(process.cwd(), 'packages/sync/sync-to-obsidian.mjs');
530
+ const syncDir = resolve(process.cwd(), 'packages/sync');
531
+ const { existsSync } = await import('node:fs');
532
+ if (!existsSync(syncScript)) {
533
+ res.json({ success: false, error: 'sync script not found' });
534
+ return;
535
+ }
536
+ if (!existsSync(resolve(syncDir, '.env'))) {
537
+ res.json({ success: false, error: '.env not found' });
538
+ return;
539
+ }
540
+ syncState = { running: true, startedAt: new Date().toISOString(), completedAt: '', result: '', output: '' };
541
+ const child = spawn('node', [syncScript], { cwd: syncDir, stdio: ['ignore', 'pipe', 'pipe'], shell: true });
542
+ let output = '';
543
+ child.stdout.on('data', (d) => { output += d.toString(); });
544
+ child.stderr.on('data', (d) => { output += d.toString(); });
545
+ child.on('close', (code) => {
546
+ syncState.running = false;
547
+ syncState.completedAt = new Date().toISOString();
548
+ syncState.result = code === 0 ? 'success' : 'failed';
549
+ syncState.output = output.slice(-500); // 마지막 500자만
550
+ });
551
+ res.json({ success: true, message: 'Sync started' });
552
+ }
553
+ catch (err) {
554
+ syncState.running = false;
555
+ console.error(err);
556
+ res.status(500).json({ error: 'Sync failed' });
557
+ }
558
+ });
559
+ // GET /api/sync/status — 동기화 상태 조회
560
+ app.get('/api/sync/status', (_req, res) => {
561
+ res.json(syncState);
562
+ });
563
+ // POST /api/clip — 웹 페이지 클리핑
564
+ app.post('/api/clip', async (req, res) => {
565
+ try {
566
+ const { url } = req.body;
567
+ if (!url) {
568
+ res.status(400).json({ error: 'url required' });
569
+ return;
570
+ }
571
+ // HIGH-03: SSRF 방어 — 내부 네트워크 차단
572
+ try {
573
+ const parsed = new URL(url);
574
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
575
+ res.status(400).json({ error: 'Only http/https URLs allowed' });
576
+ return;
577
+ }
578
+ const host = parsed.hostname.toLowerCase();
579
+ if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host.endsWith('.local') || host.startsWith('192.168.') || host.startsWith('10.') || host.startsWith('172.16.')) {
580
+ res.status(400).json({ error: 'Internal URLs not allowed' });
581
+ return;
582
+ }
583
+ }
584
+ catch {
585
+ res.status(400).json({ error: 'Invalid URL' });
586
+ return;
587
+ }
588
+ const isYT = /youtube\.com\/watch|youtu\.be\//.test(url);
589
+ const response = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0 stellavault-clipper/1.0' }, signal: AbortSignal.timeout(15000) });
590
+ const html = await response.text();
591
+ // 제목 추출
592
+ const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
593
+ let title = (titleMatch ? titleMatch[1] : new URL(url).hostname).replace(/ - YouTube$/, '').trim();
594
+ const safeTitle = title.replace(/[<>:"/\\|?*]/g, '').replace(/\s+/g, ' ').trim().slice(0, 80);
595
+ let content;
596
+ if (isYT) {
597
+ const videoId = url.match(/(?:v=|youtu\.be\/)([a-zA-Z0-9_-]+)/)?.[1] ?? '';
598
+ const descMatch = html.match(/"shortDescription":"([\s\S]*?)"/);
599
+ const desc = descMatch ? descMatch[1].replace(/\\n/g, '\n').replace(/\\"/g, '"').slice(0, 3000) : '';
600
+ content = `![thumbnail](https://img.youtube.com/vi/${videoId}/maxresdefault.jpg)\n\n## 설명\n\n${desc}\n\n[YouTube](${url})`;
601
+ }
602
+ else {
603
+ content = html
604
+ .replace(/<script[\s\S]*?<\/script>/gi, '').replace(/<style[\s\S]*?<\/style>/gi, '')
605
+ .replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, '\n# $1\n').replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, '\n## $1\n')
606
+ .replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, '\n### $1\n')
607
+ .replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, '\n$1\n').replace(/<br\s*\/?>/gi, '\n')
608
+ .replace(/<a[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, '[$2]($1)')
609
+ .replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, '- $1\n')
610
+ .replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, '**$2**')
611
+ .replace(/<(em|i)[^>]*>([\s\S]*?)<\/\1>/gi, '*$2*')
612
+ .replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, '`$1`')
613
+ .replace(/<[^>]+>/g, '')
614
+ .replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&nbsp;/g, ' ')
615
+ .replace(/\n{3,}/g, '\n\n').trim();
616
+ if (content.length > 10000)
617
+ content = content.slice(0, 10000) + '\n\n...(truncated)';
618
+ }
619
+ // vault에 저장
620
+ const { writeFileSync, mkdirSync } = await import('node:fs');
621
+ const { join } = await import('node:path');
622
+ const date = new Date().toISOString().slice(0, 10);
623
+ const clipDir = join(vaultPath || '.', '06_Research', 'clips');
624
+ mkdirSync(clipDir, { recursive: true });
625
+ const fileName = `${date} ${safeTitle}.md`;
626
+ const md = `---\ntitle: "${safeTitle}"\nsource: "${url}"\nclipped: ${date}\ntags: [clip${isYT ? ', youtube' : ''}]\n---\n\n# ${safeTitle}\n\n> Source: ${url}\n\n${content}`;
627
+ writeFileSync(join(clipDir, fileName), md, 'utf-8');
628
+ res.json({ success: true, fileName, path: join(clipDir, fileName) });
629
+ }
630
+ catch (err) {
631
+ console.error(err);
632
+ res.status(500).json({ error: 'Clip failed' });
633
+ }
634
+ });
635
+ return {
636
+ async start() {
637
+ return new Promise((resolve) => {
638
+ app.listen(port, '127.0.0.1', () => {
639
+ console.error(`🌐 API server running at http://127.0.0.1:${port}`);
640
+ resolve();
641
+ });
642
+ });
643
+ },
644
+ app,
645
+ };
646
+ }
647
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1,24 @@
1
+ export interface CaptureResult {
2
+ title: string;
3
+ filePath: string;
4
+ transcript: string;
5
+ duration?: number;
6
+ tags: string[];
7
+ success: boolean;
8
+ error?: string;
9
+ }
10
+ export interface CaptureOptions {
11
+ vaultPath: string;
12
+ folder?: string;
13
+ language?: string;
14
+ model?: string;
15
+ tags?: string[];
16
+ type?: string;
17
+ }
18
+ export declare function isWhisperAvailable(): boolean;
19
+ export declare function transcribeAudio(audioPath: string, options?: {
20
+ model?: string;
21
+ language?: string;
22
+ }): Promise<string>;
23
+ export declare function captureVoice(audioPath: string, options: CaptureOptions): Promise<CaptureResult>;
24
+ //# sourceMappingURL=voice.d.ts.map