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,142 +0,0 @@
1
- // Design Ref: §6 — Indexer (scanner: glob + frontmatter 파싱)
2
-
3
- import { readdirSync, readFileSync, statSync } from 'node:fs';
4
- import { join, relative, extname } from 'node:path';
5
- import { createHash } from 'node:crypto';
6
- import matter from 'gray-matter';
7
- import type { Document } from '../types/document.js';
8
-
9
- export interface ScanResult {
10
- documents: Document[];
11
- scannedFiles: number;
12
- skippedFiles: number;
13
- }
14
-
15
- /**
16
- * vault 디렉토리에서 모든 .md 파일을 스캔하여 Document 목록 반환
17
- */
18
- export function scanVault(vaultPath: string): ScanResult {
19
- const documents: Document[] = [];
20
- let skippedFiles = 0;
21
-
22
- const mdFiles = findMdFiles(vaultPath);
23
-
24
- for (const filePath of mdFiles) {
25
- try {
26
- const doc = parseDocument(vaultPath, filePath);
27
- documents.push(doc);
28
- } catch {
29
- skippedFiles++;
30
- }
31
- }
32
-
33
- return { documents, scannedFiles: mdFiles.length, skippedFiles };
34
- }
35
-
36
- function findMdFiles(dir: string, files: string[] = []): string[] {
37
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
38
- const fullPath = join(dir, entry.name);
39
- if (entry.isDirectory()) {
40
- if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'zh-CN') continue;
41
- findMdFiles(fullPath, files);
42
- } else if (extname(entry.name) === '.md') {
43
- files.push(fullPath);
44
- }
45
- }
46
- return files;
47
- }
48
-
49
- function parseDocument(vaultPath: string, filePath: string): Document {
50
- const raw = readFileSync(filePath, 'utf-8');
51
- const stat = statSync(filePath);
52
- const { data: frontmatter, content } = matter(raw);
53
-
54
- const relativePath = relative(vaultPath, filePath).replace(/\\/g, '/');
55
- const id = createHash('sha256').update(relativePath).digest('hex').slice(0, 16);
56
- const contentHash = createHash('sha256').update(raw).digest('hex').slice(0, 16);
57
-
58
- const title = (frontmatter.title as string)
59
- ?? extractFirstHeading(content)
60
- ?? relativePath.replace(/\.md$/, '');
61
-
62
- const tags = extractTags(frontmatter, content);
63
-
64
- // source/type 자동 추출 (원본 파일 수정 없이 DB에만 저장)
65
- const source = inferSource(frontmatter, relativePath);
66
- const type = inferType(frontmatter, relativePath);
67
-
68
- return {
69
- id,
70
- filePath: relativePath,
71
- title,
72
- content,
73
- frontmatter,
74
- tags,
75
- lastModified: stat.mtime.toISOString(),
76
- contentHash,
77
- source,
78
- type,
79
- };
80
- }
81
-
82
- function inferSource(frontmatter: Record<string, unknown>, filePath: string): string {
83
- // frontmatter에 명시된 경우
84
- if (frontmatter.source && typeof frontmatter.source === 'string') {
85
- if (frontmatter.source.startsWith('http')) return 'clip';
86
- return frontmatter.source;
87
- }
88
- // 경로 기반 추론
89
- if (filePath.includes('clips/') || filePath.includes('clip/')) return 'clip';
90
- if (filePath.includes('PDCA') || filePath.includes('pdca')) return 'local';
91
- if (frontmatter['x-i18n']) return 'notion'; // Notion 번역 문서
92
- if (frontmatter.clipped) return 'clip';
93
- return 'local';
94
- }
95
-
96
- function inferType(frontmatter: Record<string, unknown>, filePath: string): string {
97
- // frontmatter에 명시된 경우
98
- if (frontmatter.type && typeof frontmatter.type === 'string') return frontmatter.type;
99
- // tags 기반
100
- const tags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
101
- if (tags.includes('bridge') || tags.includes('auto-generated')) return 'bridge';
102
- if (tags.includes('clip') || tags.includes('youtube')) return 'clip';
103
- if (tags.includes('decision')) return 'decision';
104
- // 경로 기반
105
- if (filePath.includes('clips/')) return 'clip';
106
- if (filePath.includes('Decisions/') || filePath.includes('decisions/')) return 'decision';
107
- if (filePath.includes('Sessions/') || filePath.includes('sessions/')) return 'session';
108
- if (filePath.includes('Research/')) return 'research';
109
- if (filePath.includes('Lessons/')) return 'lesson';
110
- if (filePath.includes('Templates/')) return 'template';
111
- return 'note';
112
- }
113
-
114
- function extractFirstHeading(content: string): string | null {
115
- const match = content.match(/^#\s+(.+)$/m);
116
- return match ? match[1].trim() : null;
117
- }
118
-
119
- function extractTags(frontmatter: Record<string, unknown>, content: string): string[] {
120
- const tags = new Set<string>();
121
-
122
- // frontmatter tags
123
- const fmTags = frontmatter.tags;
124
- if (Array.isArray(fmTags)) {
125
- fmTags.forEach(t => tags.add(String(t)));
126
- } else if (typeof fmTags === 'string') {
127
- fmTags.split(',').map(t => t.trim()).filter(Boolean).forEach(t => tags.add(t));
128
- }
129
-
130
- // inline #tags (CSS 컬러코드, 순수 숫자, heading # 제외)
131
- const inlineTags = content.match(/(?:^|\s)#([a-zA-Z가-힣][a-zA-Z가-힣\w-]*)/g);
132
- if (inlineTags) {
133
- for (const raw of inlineTags) {
134
- const tag = raw.trim().slice(1);
135
- // CSS hex 컬러 (#fff, #6c5ce7 등) 제외
136
- if (/^[0-9a-fA-F]{3,8}$/.test(tag)) continue;
137
- tags.add(tag);
138
- }
139
- }
140
-
141
- return [...tags];
142
- }
@@ -1,62 +0,0 @@
1
- // Design Ref: §6.3 — 파일 감시 + 증분 인덱싱 (debounce 5s)
2
-
3
- import { watch, type FSWatcher } from 'chokidar';
4
- import { extname } from 'node:path';
5
- import type { Embedder } from './embedder.js';
6
- import type { VectorStore } from '../store/types.js';
7
- import { indexVault } from './index.js';
8
- import type { ChunkOptions } from './chunker.js';
9
-
10
- export interface WatcherOptions {
11
- vaultPath: string;
12
- store: VectorStore;
13
- embedder: Embedder;
14
- chunkOptions?: Partial<ChunkOptions>;
15
- debounceMs?: number;
16
- onReindex?: (result: { indexed: number; skipped: number }) => void;
17
- }
18
-
19
- export function createWatcher(options: WatcherOptions): { start(): void; stop(): void } {
20
- const { vaultPath, store, embedder, chunkOptions, debounceMs = 5000, onReindex } = options;
21
- let watcher: FSWatcher | null = null;
22
- let debounceTimer: ReturnType<typeof setTimeout> | null = null;
23
- let reindexing = false;
24
-
25
- async function triggerReindex() {
26
- if (reindexing) return;
27
- reindexing = true;
28
- try {
29
- const result = await indexVault(vaultPath, { store, embedder, chunkOptions });
30
- onReindex?.({ indexed: result.indexed, skipped: result.skipped });
31
- } finally {
32
- reindexing = false;
33
- }
34
- }
35
-
36
- function scheduleReindex() {
37
- if (debounceTimer) clearTimeout(debounceTimer);
38
- debounceTimer = setTimeout(() => triggerReindex(), debounceMs);
39
- }
40
-
41
- return {
42
- start() {
43
- watcher = watch(vaultPath, {
44
- ignored: /(^|[\/\\])\.|node_modules/,
45
- persistent: true,
46
- ignoreInitial: true,
47
- });
48
-
49
- watcher.on('all', (event, path) => {
50
- if (extname(path) !== '.md') return;
51
- if (['add', 'change', 'unlink'].includes(event)) {
52
- scheduleReindex();
53
- }
54
- });
55
- },
56
-
57
- stop() {
58
- if (debounceTimer) clearTimeout(debounceTimer);
59
- watcher?.close();
60
- },
61
- };
62
- }
@@ -1,134 +0,0 @@
1
- // Contradiction Detector (F-A12)
2
- // Finds potentially contradicting statements across notes
3
- // Uses embedding similarity + negation pattern detection
4
-
5
- import type { VectorStore } from '../store/types.js';
6
-
7
- export interface ContradictionPair {
8
- docA: { id: string; title: string; filePath: string; statement: string };
9
- docB: { id: string; title: string; filePath: string; statement: string };
10
- similarity: number;
11
- confidence: number; // 0-1, how likely this is a real contradiction
12
- type: 'negation' | 'value_conflict' | 'temporal' | 'semantic';
13
- }
14
-
15
- // Negation/opposition patterns
16
- const NEGATION_PAIRS = [
17
- ['should', 'should not'], ['must', 'must not'], ['always', 'never'],
18
- ['best', 'worst'], ['good', 'bad'], ['correct', 'incorrect'],
19
- ['true', 'false'], ['increase', 'decrease'], ['enable', 'disable'],
20
- ['recommended', 'not recommended'], ['use', 'avoid'],
21
- ['prefer', 'avoid'], ['do', "don't"], ['is', "isn't"],
22
- ['can', "can't"], ['will', "won't"], ['important', 'unimportant'],
23
- ['필요', '불필요'], ['해야', '하면 안'], ['좋', '나쁜'], ['맞', '틀'],
24
- ];
25
-
26
- function extractKeyStatements(content: string): string[] {
27
- return content
28
- .split(/[.\n!?]/)
29
- .map(s => s.trim())
30
- .filter(s => s.length > 20 && s.length < 200)
31
- .filter(s => {
32
- const lower = s.toLowerCase();
33
- return /should|must|always|never|best|important|recommend|prefer|avoid|필요|해야|좋|나쁜/.test(lower);
34
- })
35
- .slice(0, 10); // max 10 statements per document
36
- }
37
-
38
- function detectNegationConflict(stmtA: string, stmtB: string): { isConflict: boolean; confidence: number; type: ContradictionPair['type'] } {
39
- const a = stmtA.toLowerCase();
40
- const b = stmtB.toLowerCase();
41
-
42
- // Check negation pairs
43
- for (const [pos, neg] of NEGATION_PAIRS) {
44
- if ((a.includes(pos) && b.includes(neg)) || (a.includes(neg) && b.includes(pos))) {
45
- // Check if they're talking about the same subject (share words)
46
- const wordsA = new Set(a.split(/\s+/).filter(w => w.length > 3));
47
- const wordsB = new Set(b.split(/\s+/).filter(w => w.length > 3));
48
- const overlap = [...wordsA].filter(w => wordsB.has(w)).length;
49
- const minSize = Math.min(wordsA.size, wordsB.size) || 1;
50
- const subjectOverlap = overlap / minSize;
51
-
52
- if (subjectOverlap > 0.2) {
53
- return { isConflict: true, confidence: Math.min(0.5 + subjectOverlap * 0.5, 0.95), type: 'negation' };
54
- }
55
- }
56
- }
57
-
58
- // Check numeric value conflicts (e.g., "timeout should be 30s" vs "timeout should be 5s")
59
- const numsA = a.match(/\d+/g);
60
- const numsB = b.match(/\d+/g);
61
- if (numsA && numsB) {
62
- const wordsA = new Set(a.replace(/\d+/g, '').split(/\s+/).filter(w => w.length > 3));
63
- const wordsB = new Set(b.replace(/\d+/g, '').split(/\s+/).filter(w => w.length > 3));
64
- const overlap = [...wordsA].filter(w => wordsB.has(w)).length;
65
- if (overlap >= 2 && numsA[0] !== numsB[0]) {
66
- return { isConflict: true, confidence: 0.6, type: 'value_conflict' };
67
- }
68
- }
69
-
70
- return { isConflict: false, confidence: 0, type: 'semantic' };
71
- }
72
-
73
- export async function detectContradictions(
74
- store: VectorStore,
75
- limit = 20,
76
- ): Promise<ContradictionPair[]> {
77
- const docs = await store.getAllDocuments();
78
- const embeddings = await store.getDocumentEmbeddings();
79
-
80
- if (docs.length < 2) return [];
81
-
82
- // Build document vectors + key statements
83
- const docData = new Map<string, { vec: number[]; title: string; filePath: string; statements: string[] }>();
84
- for (const doc of docs) {
85
- const vec = embeddings.get(doc.id);
86
- if (!vec) continue;
87
- const statements = extractKeyStatements(doc.content);
88
- if (statements.length === 0) continue;
89
- docData.set(doc.id, { vec: Array.from(vec), title: doc.title, filePath: doc.filePath, statements });
90
- }
91
-
92
- const ids = [...docData.keys()];
93
- const results: ContradictionPair[] = [];
94
-
95
- // Compare documents with moderate similarity (same topic, possibly conflicting)
96
- for (let i = 0; i < ids.length && results.length < limit * 3; i++) {
97
- for (let j = i + 1; j < ids.length && results.length < limit * 3; j++) {
98
- const a = docData.get(ids[i])!;
99
- const b = docData.get(ids[j])!;
100
- const sim = cosineSim(a.vec, b.vec);
101
-
102
- // Sweet spot: similar enough to be same topic, not identical
103
- if (sim < 0.3 || sim > 0.9) continue;
104
-
105
- // Compare statements
106
- for (const stmtA of a.statements) {
107
- for (const stmtB of b.statements) {
108
- const { isConflict, confidence, type } = detectNegationConflict(stmtA, stmtB);
109
- if (isConflict && confidence >= 0.5) {
110
- results.push({
111
- docA: { id: ids[i], title: a.title, filePath: a.filePath, statement: stmtA },
112
- docB: { id: ids[j], title: b.title, filePath: b.filePath, statement: stmtB },
113
- similarity: Math.round(sim * 1000) / 1000,
114
- confidence: Math.round(confidence * 100) / 100,
115
- type,
116
- });
117
- }
118
- }
119
- }
120
- }
121
- }
122
-
123
- return results
124
- .sort((a, b) => b.confidence - a.confidence)
125
- .slice(0, limit);
126
- }
127
-
128
- function cosineSim(a: number[], b: number[]): number {
129
- if (a.length !== b.length) return 0;
130
- let dot = 0, na = 0, nb = 0;
131
- for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i]; }
132
- const d = Math.sqrt(na) * Math.sqrt(nb);
133
- return d === 0 ? 0 : dot / d;
134
- }
@@ -1,229 +0,0 @@
1
- // Design Ref: §3.2 — 감쇠 엔진 (DB 연동)
2
- // Plan SC: SC-01, SC-02, SC-04
3
-
4
- import type { Database } from 'better-sqlite3';
5
- import type { DecayState, AccessEvent, DecayReport } from './types.js';
6
- import {
7
- computeRetrievability,
8
- updateStability,
9
- estimateInitialStability,
10
- elapsedDays,
11
- FSRS_PARAMS,
12
- } from './fsrs.js';
13
-
14
- export class DecayEngine {
15
- constructor(private db: Database) {
16
- this.ensureTables();
17
- }
18
-
19
- private ensureTables() {
20
- this.db.exec(`
21
- CREATE TABLE IF NOT EXISTS access_log (
22
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23
- document_id TEXT NOT NULL,
24
- access_type TEXT NOT NULL,
25
- accessed_at TEXT NOT NULL
26
- );
27
- CREATE INDEX IF NOT EXISTS idx_access_log_doc ON access_log(document_id);
28
- CREATE INDEX IF NOT EXISTS idx_access_log_time ON access_log(accessed_at);
29
-
30
- CREATE TABLE IF NOT EXISTS decay_state (
31
- document_id TEXT PRIMARY KEY,
32
- stability REAL NOT NULL DEFAULT 7.0,
33
- difficulty REAL NOT NULL DEFAULT 5.0,
34
- last_access TEXT NOT NULL,
35
- retrievability REAL NOT NULL DEFAULT 1.0,
36
- updated_at TEXT NOT NULL
37
- );
38
- `);
39
- }
40
-
41
- /**
42
- * Record an access event and update decay state.
43
- */
44
- async recordAccess(event: AccessEvent): Promise<void> {
45
- const now = event.timestamp || new Date().toISOString();
46
-
47
- // Log the event
48
- this.db.prepare(
49
- 'INSERT INTO access_log (document_id, access_type, accessed_at) VALUES (?, ?, ?)'
50
- ).run(event.documentId, event.type, now);
51
-
52
- // Get or create decay state
53
- const existing = this.db.prepare(
54
- 'SELECT * FROM decay_state WHERE document_id = ?'
55
- ).get(event.documentId) as any;
56
-
57
- if (existing) {
58
- const elapsed = elapsedDays(existing.last_access, now);
59
- const currentR = computeRetrievability(existing.stability, elapsed);
60
- const newS = updateStability(existing.stability, existing.difficulty, currentR);
61
-
62
- this.db.prepare(`
63
- UPDATE decay_state SET stability = ?, last_access = ?, retrievability = 1.0, updated_at = ?
64
- WHERE document_id = ?
65
- `).run(newS, now, now, event.documentId);
66
- } else {
67
- // New document — estimate initial stability
68
- const doc = this.db.prepare('SELECT content FROM documents WHERE id = ?').get(event.documentId) as any;
69
- const contentLen = doc?.content?.length ?? 500;
70
- const connCount = (this.db.prepare(
71
- 'SELECT COUNT(*) as c FROM chunks WHERE document_id = ?'
72
- ).get(event.documentId) as any)?.c ?? 1;
73
- const initS = estimateInitialStability(contentLen, connCount);
74
-
75
- this.db.prepare(`
76
- INSERT INTO decay_state (document_id, stability, difficulty, last_access, retrievability, updated_at)
77
- VALUES (?, ?, ?, ?, 1.0, ?)
78
- `).run(event.documentId, initS, FSRS_PARAMS.difficulty, now, now);
79
- }
80
- }
81
-
82
- /**
83
- * Batch compute retrievability for all documents.
84
- */
85
- async computeAll(): Promise<DecayReport> {
86
- const now = new Date().toISOString();
87
-
88
- // Initialize documents that don't have decay state yet
89
- await this.initializeNewDocuments();
90
-
91
- // Compute R for all
92
- const states = this.db.prepare('SELECT * FROM decay_state').all() as any[];
93
- const docs = this.db.prepare('SELECT id, title FROM documents').all() as any[];
94
- const titleMap = new Map(docs.map((d: any) => [d.id, d.title]));
95
-
96
- const updated: DecayState[] = [];
97
- const updateStmt = this.db.prepare(
98
- 'UPDATE decay_state SET retrievability = ?, updated_at = ? WHERE document_id = ?'
99
- );
100
-
101
- const tx = this.db.transaction(() => {
102
- for (const s of states) {
103
- const elapsed = elapsedDays(s.last_access, now);
104
- const r = computeRetrievability(s.stability, elapsed);
105
- updateStmt.run(r, now, s.document_id);
106
- updated.push({
107
- documentId: s.document_id,
108
- stability: s.stability,
109
- difficulty: s.difficulty,
110
- lastAccess: s.last_access,
111
- retrievability: r,
112
- });
113
- }
114
- });
115
- tx();
116
-
117
- // Build report
118
- const decaying = updated.filter(s => s.retrievability < 0.5);
119
- const critical = updated.filter(s => s.retrievability < 0.3);
120
- const avgR = updated.length > 0
121
- ? updated.reduce((sum, s) => sum + s.retrievability, 0) / updated.length
122
- : 1.0;
123
-
124
- // Top decaying (sorted by R ascending)
125
- const topDecaying = [...decaying]
126
- .sort((a, b) => a.retrievability - b.retrievability)
127
- .slice(0, 20)
128
- .map(s => ({
129
- ...s,
130
- title: titleMap.get(s.documentId) ?? s.documentId,
131
- daysSinceAccess: Math.round(elapsedDays(s.lastAccess, now)),
132
- }));
133
-
134
- // Cluster health
135
- const clusterData = this.db.prepare(`
136
- SELECT ds.document_id, ds.retrievability
137
- FROM decay_state ds
138
- JOIN documents d ON d.id = ds.document_id
139
- `).all() as any[];
140
-
141
- // Get cluster info from graph data cache (simplified: group by first folder)
142
- const clusterHealth = this.computeClusterHealth(clusterData);
143
-
144
- return {
145
- totalDocuments: updated.length,
146
- decayingCount: decaying.length,
147
- criticalCount: critical.length,
148
- averageR: Math.round(avgR * 100) / 100,
149
- topDecaying,
150
- clusterHealth,
151
- };
152
- }
153
-
154
- private computeClusterHealth(data: any[]): DecayReport['clusterHealth'] {
155
- // Group by document's top-level folder as proxy for cluster
156
- const groups = new Map<string, number[]>();
157
- for (const row of data) {
158
- const doc = this.db.prepare('SELECT file_path FROM documents WHERE id = ?').get(row.document_id) as any;
159
- const folder = doc?.file_path?.split('/')[0] ?? 'unknown';
160
- if (!groups.has(folder)) groups.set(folder, []);
161
- groups.get(folder)!.push(row.retrievability);
162
- }
163
-
164
- return [...groups.entries()]
165
- .map(([label, rs]) => ({
166
- label,
167
- avgR: Math.round((rs.reduce((a, b) => a + b, 0) / rs.length) * 100) / 100,
168
- count: rs.length,
169
- }))
170
- .sort((a, b) => a.avgR - b.avgR);
171
- }
172
-
173
- /**
174
- * Get documents below decay threshold.
175
- */
176
- async getDecaying(threshold = 0.5, limit = 20): Promise<Array<DecayState & { title: string }>> {
177
- await this.computeAll(); // refresh R values
178
-
179
- const rows = this.db.prepare(`
180
- SELECT ds.*, d.title FROM decay_state ds
181
- JOIN documents d ON d.id = ds.document_id
182
- WHERE ds.retrievability < ?
183
- ORDER BY ds.retrievability ASC
184
- LIMIT ?
185
- `).all(threshold, limit) as any[];
186
-
187
- return rows.map(r => ({
188
- documentId: r.document_id,
189
- stability: r.stability,
190
- difficulty: r.difficulty,
191
- lastAccess: r.last_access,
192
- retrievability: r.retrievability,
193
- title: r.title,
194
- }));
195
- }
196
-
197
- /**
198
- * Initialize decay state for documents that don't have one yet.
199
- */
200
- async initializeNewDocuments(): Promise<number> {
201
- const missing = this.db.prepare(`
202
- SELECT d.id, d.content, d.last_modified
203
- FROM documents d
204
- LEFT JOIN decay_state ds ON d.id = ds.document_id
205
- WHERE ds.document_id IS NULL
206
- `).all() as any[];
207
-
208
- if (missing.length === 0) return 0;
209
-
210
- const insert = this.db.prepare(`
211
- INSERT OR IGNORE INTO decay_state (document_id, stability, difficulty, last_access, retrievability, updated_at)
212
- VALUES (?, ?, ?, ?, ?, ?)
213
- `);
214
-
215
- const tx = this.db.transaction(() => {
216
- for (const doc of missing) {
217
- const contentLen = doc.content?.length ?? 500;
218
- const initS = estimateInitialStability(contentLen, 1);
219
- const lastAccess = doc.last_modified || new Date().toISOString();
220
- const elapsed = elapsedDays(lastAccess);
221
- const r = computeRetrievability(initS, elapsed);
222
- insert.run(doc.id, initS, FSRS_PARAMS.difficulty, lastAccess, r, new Date().toISOString());
223
- }
224
- });
225
- tx();
226
-
227
- return missing.length;
228
- }
229
- }
@@ -1,71 +0,0 @@
1
- // Design Ref: 중복/유사 노트 탐지
2
- // 기존 벡터 임베딩의 cosine similarity 활용
3
-
4
- import type { VectorStore } from '../store/types.js';
5
-
6
- export interface DuplicatePair {
7
- docA: { id: string; title: string; filePath: string };
8
- docB: { id: string; title: string; filePath: string };
9
- similarity: number;
10
- }
11
-
12
- /**
13
- * 벡터 유사도 기반 중복 노트 탐지.
14
- * 문서별 평균 임베딩을 비교하여 threshold 이상인 쌍을 반환.
15
- */
16
- export async function detectDuplicates(
17
- store: VectorStore,
18
- threshold = 0.88,
19
- limit = 20,
20
- ): Promise<DuplicatePair[]> {
21
- const docs = await store.getAllDocuments();
22
- const embeddings = await store.getDocumentEmbeddings();
23
-
24
- if (docs.length < 2) return [];
25
-
26
- // 문서별 평균 임베딩 계산
27
- const docVecs = new Map<string, { vec: number[]; title: string; filePath: string }>();
28
- for (const doc of docs) {
29
- const vec = embeddings.get(doc.id);
30
- if (!vec || vec.length === 0) continue;
31
- docVecs.set(doc.id, { vec: Array.from(vec), title: doc.title, filePath: doc.filePath });
32
- }
33
-
34
- const ids = [...docVecs.keys()];
35
- const pairs: DuplicatePair[] = [];
36
-
37
- // O(n²) — 1,200 문서면 ~720K 비교, 수 초 이내
38
- for (let i = 0; i < ids.length; i++) {
39
- for (let j = i + 1; j < ids.length; j++) {
40
- const a = docVecs.get(ids[i])!;
41
- const b = docVecs.get(ids[j])!;
42
- const sim = cosineSimilarity(a.vec, b.vec);
43
-
44
- if (sim >= threshold) {
45
- pairs.push({
46
- docA: { id: ids[i], title: a.title, filePath: a.filePath },
47
- docB: { id: ids[j], title: b.title, filePath: b.filePath },
48
- similarity: Math.round(sim * 1000) / 1000,
49
- });
50
- }
51
- }
52
-
53
- if (pairs.length >= limit * 2) break; // 충분히 찾으면 중단
54
- }
55
-
56
- return pairs
57
- .sort((a, b) => b.similarity - a.similarity)
58
- .slice(0, limit);
59
- }
60
-
61
- function cosineSimilarity(a: number[], b: number[]): number {
62
- if (a.length !== b.length) return 0;
63
- let dot = 0, normA = 0, normB = 0;
64
- for (let i = 0; i < a.length; i++) {
65
- dot += a[i] * b[i];
66
- normA += a[i] * a[i];
67
- normB += b[i] * b[i];
68
- }
69
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
70
- return denom === 0 ? 0 : dot / denom;
71
- }