stellavault 0.4.4 → 0.5.0

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 (265) hide show
  1. package/README.md +52 -16
  2. package/SECURITY.md +50 -0
  3. package/dist/stellavault.js +8968 -0
  4. package/package.json +70 -33
  5. package/.env.example +0 -12
  6. package/CHANGELOG.md +0 -106
  7. package/CLAUDE.md +0 -42
  8. package/CONTRIBUTING.md +0 -65
  9. package/index.html +0 -509
  10. package/packages/cli/bin/ekh.js +0 -2
  11. package/packages/cli/bin/stellavault.js +0 -2
  12. package/packages/cli/dist/commands/adr-cmd.d.ts +0 -7
  13. package/packages/cli/dist/commands/adr-cmd.js +0 -45
  14. package/packages/cli/dist/commands/ask-cmd.d.ts +0 -5
  15. package/packages/cli/dist/commands/ask-cmd.js +0 -36
  16. package/packages/cli/dist/commands/autopilot-cmd.d.ts +0 -4
  17. package/packages/cli/dist/commands/autopilot-cmd.js +0 -76
  18. package/packages/cli/dist/commands/brief-cmd.d.ts +0 -2
  19. package/packages/cli/dist/commands/brief-cmd.js +0 -82
  20. package/packages/cli/dist/commands/capture-cmd.d.ts +0 -7
  21. package/packages/cli/dist/commands/capture-cmd.js +0 -31
  22. package/packages/cli/dist/commands/card-cmd.d.ts +0 -4
  23. package/packages/cli/dist/commands/card-cmd.js +0 -26
  24. package/packages/cli/dist/commands/clip-cmd.d.ts +0 -4
  25. package/packages/cli/dist/commands/clip-cmd.js +0 -151
  26. package/packages/cli/dist/commands/cloud-cmd.d.ts +0 -4
  27. package/packages/cli/dist/commands/cloud-cmd.js +0 -64
  28. package/packages/cli/dist/commands/compile-cmd.d.ts +0 -6
  29. package/packages/cli/dist/commands/compile-cmd.js +0 -30
  30. package/packages/cli/dist/commands/contradictions-cmd.d.ts +0 -2
  31. package/packages/cli/dist/commands/contradictions-cmd.js +0 -34
  32. package/packages/cli/dist/commands/decay-cmd.d.ts +0 -2
  33. package/packages/cli/dist/commands/decay-cmd.js +0 -48
  34. package/packages/cli/dist/commands/digest-cmd.d.ts +0 -5
  35. package/packages/cli/dist/commands/digest-cmd.js +0 -136
  36. package/packages/cli/dist/commands/draft-cmd.d.ts +0 -6
  37. package/packages/cli/dist/commands/draft-cmd.js +0 -110
  38. package/packages/cli/dist/commands/duplicates-cmd.d.ts +0 -4
  39. package/packages/cli/dist/commands/duplicates-cmd.js +0 -30
  40. package/packages/cli/dist/commands/federate-cmd.d.ts +0 -5
  41. package/packages/cli/dist/commands/federate-cmd.js +0 -247
  42. package/packages/cli/dist/commands/fleeting-cmd.d.ts +0 -4
  43. package/packages/cli/dist/commands/fleeting-cmd.js +0 -45
  44. package/packages/cli/dist/commands/flush-cmd.d.ts +0 -2
  45. package/packages/cli/dist/commands/flush-cmd.js +0 -58
  46. package/packages/cli/dist/commands/gaps-cmd.d.ts +0 -2
  47. package/packages/cli/dist/commands/gaps-cmd.js +0 -33
  48. package/packages/cli/dist/commands/graph-cmd.d.ts +0 -2
  49. package/packages/cli/dist/commands/graph-cmd.js +0 -89
  50. package/packages/cli/dist/commands/index-cmd.d.ts +0 -2
  51. package/packages/cli/dist/commands/index-cmd.js +0 -57
  52. package/packages/cli/dist/commands/ingest-cmd.d.ts +0 -9
  53. package/packages/cli/dist/commands/ingest-cmd.js +0 -195
  54. package/packages/cli/dist/commands/init-cmd.d.ts +0 -2
  55. package/packages/cli/dist/commands/init-cmd.js +0 -161
  56. package/packages/cli/dist/commands/learn-cmd.d.ts +0 -2
  57. package/packages/cli/dist/commands/learn-cmd.js +0 -48
  58. package/packages/cli/dist/commands/lint-cmd.d.ts +0 -2
  59. package/packages/cli/dist/commands/lint-cmd.js +0 -61
  60. package/packages/cli/dist/commands/pack-cmd.d.ts +0 -15
  61. package/packages/cli/dist/commands/pack-cmd.js +0 -93
  62. package/packages/cli/dist/commands/review-cmd.d.ts +0 -4
  63. package/packages/cli/dist/commands/review-cmd.js +0 -107
  64. package/packages/cli/dist/commands/search-cmd.d.ts +0 -4
  65. package/packages/cli/dist/commands/search-cmd.js +0 -38
  66. package/packages/cli/dist/commands/serve-cmd.d.ts +0 -2
  67. package/packages/cli/dist/commands/serve-cmd.js +0 -14
  68. package/packages/cli/dist/commands/session-cmd.d.ts +0 -7
  69. package/packages/cli/dist/commands/session-cmd.js +0 -95
  70. package/packages/cli/dist/commands/status-cmd.d.ts +0 -2
  71. package/packages/cli/dist/commands/status-cmd.js +0 -33
  72. package/packages/cli/dist/commands/sync-cmd.d.ts +0 -5
  73. package/packages/cli/dist/commands/sync-cmd.js +0 -62
  74. package/packages/cli/dist/commands/vault-cmd.d.ts +0 -10
  75. package/packages/cli/dist/commands/vault-cmd.js +0 -54
  76. package/packages/cli/dist/index.d.ts +0 -2
  77. package/packages/cli/dist/index.js +0 -233
  78. package/packages/cli/package.json +0 -24
  79. package/packages/core/dist/api/dashboard.d.ts +0 -3
  80. package/packages/core/dist/api/dashboard.js +0 -135
  81. package/packages/core/dist/api/graph-data.d.ts +0 -11
  82. package/packages/core/dist/api/graph-data.js +0 -255
  83. package/packages/core/dist/api/pwa.d.ts +0 -3
  84. package/packages/core/dist/api/pwa.js +0 -77
  85. package/packages/core/dist/api/server.d.ts +0 -16
  86. package/packages/core/dist/api/server.js +0 -1122
  87. package/packages/core/dist/capture/voice.d.ts +0 -24
  88. package/packages/core/dist/capture/voice.js +0 -135
  89. package/packages/core/dist/cloud/index.d.ts +0 -3
  90. package/packages/core/dist/cloud/index.js +0 -2
  91. package/packages/core/dist/cloud/sync.d.ts +0 -29
  92. package/packages/core/dist/cloud/sync.js +0 -137
  93. package/packages/core/dist/config.d.ts +0 -35
  94. package/packages/core/dist/config.js +0 -63
  95. package/packages/core/dist/federation/credits.d.ts +0 -26
  96. package/packages/core/dist/federation/credits.js +0 -56
  97. package/packages/core/dist/federation/identity.d.ts +0 -14
  98. package/packages/core/dist/federation/identity.js +0 -74
  99. package/packages/core/dist/federation/index.d.ts +0 -7
  100. package/packages/core/dist/federation/index.js +0 -5
  101. package/packages/core/dist/federation/node.d.ts +0 -31
  102. package/packages/core/dist/federation/node.js +0 -216
  103. package/packages/core/dist/federation/privacy.d.ts +0 -8
  104. package/packages/core/dist/federation/privacy.js +0 -40
  105. package/packages/core/dist/federation/reputation.d.ts +0 -37
  106. package/packages/core/dist/federation/reputation.js +0 -139
  107. package/packages/core/dist/federation/search.d.ts +0 -19
  108. package/packages/core/dist/federation/search.js +0 -101
  109. package/packages/core/dist/federation/sharing.d.ts +0 -72
  110. package/packages/core/dist/federation/sharing.js +0 -246
  111. package/packages/core/dist/federation/trust.d.ts +0 -15
  112. package/packages/core/dist/federation/trust.js +0 -60
  113. package/packages/core/dist/federation/types.d.ts +0 -40
  114. package/packages/core/dist/federation/types.js +0 -3
  115. package/packages/core/dist/i18n/index.d.ts +0 -6
  116. package/packages/core/dist/i18n/index.js +0 -81
  117. package/packages/core/dist/i18n/note-strings.d.ts +0 -5
  118. package/packages/core/dist/i18n/note-strings.js +0 -94
  119. package/packages/core/dist/index.d.ts +0 -123
  120. package/packages/core/dist/index.js +0 -74
  121. package/packages/core/dist/indexer/chunker.d.ts +0 -14
  122. package/packages/core/dist/indexer/chunker.js +0 -148
  123. package/packages/core/dist/indexer/embedder.d.ts +0 -8
  124. package/packages/core/dist/indexer/embedder.js +0 -3
  125. package/packages/core/dist/indexer/index.d.ts +0 -28
  126. package/packages/core/dist/indexer/index.js +0 -74
  127. package/packages/core/dist/indexer/local-embedder.d.ts +0 -3
  128. package/packages/core/dist/indexer/local-embedder.js +0 -29
  129. package/packages/core/dist/indexer/scanner.d.ts +0 -11
  130. package/packages/core/dist/indexer/scanner.js +0 -148
  131. package/packages/core/dist/indexer/watcher.d.ts +0 -19
  132. package/packages/core/dist/indexer/watcher.js +0 -49
  133. package/packages/core/dist/intelligence/ask-engine.d.ts +0 -24
  134. package/packages/core/dist/intelligence/ask-engine.js +0 -142
  135. package/packages/core/dist/intelligence/auto-linker.d.ts +0 -19
  136. package/packages/core/dist/intelligence/auto-linker.js +0 -126
  137. package/packages/core/dist/intelligence/code-linker.d.ts +0 -20
  138. package/packages/core/dist/intelligence/code-linker.js +0 -88
  139. package/packages/core/dist/intelligence/contradiction-detector.d.ts +0 -20
  140. package/packages/core/dist/intelligence/contradiction-detector.js +0 -115
  141. package/packages/core/dist/intelligence/decay-engine.d.ts +0 -27
  142. package/packages/core/dist/intelligence/decay-engine.js +0 -190
  143. package/packages/core/dist/intelligence/draft-generator.d.ts +0 -25
  144. package/packages/core/dist/intelligence/draft-generator.js +0 -277
  145. package/packages/core/dist/intelligence/duplicate-detector.d.ts +0 -20
  146. package/packages/core/dist/intelligence/duplicate-detector.js +0 -55
  147. package/packages/core/dist/intelligence/file-extractors.d.ts +0 -13
  148. package/packages/core/dist/intelligence/file-extractors.js +0 -155
  149. package/packages/core/dist/intelligence/fsrs.d.ts +0 -43
  150. package/packages/core/dist/intelligence/fsrs.js +0 -70
  151. package/packages/core/dist/intelligence/gap-detector.d.ts +0 -25
  152. package/packages/core/dist/intelligence/gap-detector.js +0 -78
  153. package/packages/core/dist/intelligence/ingest-pipeline.d.ts +0 -32
  154. package/packages/core/dist/intelligence/ingest-pipeline.js +0 -245
  155. package/packages/core/dist/intelligence/knowledge-lint.d.ts +0 -27
  156. package/packages/core/dist/intelligence/knowledge-lint.js +0 -132
  157. package/packages/core/dist/intelligence/learning-path.d.ts +0 -31
  158. package/packages/core/dist/intelligence/learning-path.js +0 -53
  159. package/packages/core/dist/intelligence/notifications.d.ts +0 -31
  160. package/packages/core/dist/intelligence/notifications.js +0 -65
  161. package/packages/core/dist/intelligence/predictive-gaps.d.ts +0 -14
  162. package/packages/core/dist/intelligence/predictive-gaps.js +0 -74
  163. package/packages/core/dist/intelligence/semantic-versioning.d.ts +0 -37
  164. package/packages/core/dist/intelligence/semantic-versioning.js +0 -68
  165. package/packages/core/dist/intelligence/types.d.ts +0 -28
  166. package/packages/core/dist/intelligence/types.js +0 -3
  167. package/packages/core/dist/intelligence/wiki-compiler.d.ts +0 -30
  168. package/packages/core/dist/intelligence/wiki-compiler.js +0 -222
  169. package/packages/core/dist/intelligence/youtube-extractor.d.ts +0 -29
  170. package/packages/core/dist/intelligence/youtube-extractor.js +0 -321
  171. package/packages/core/dist/intelligence/zettelkasten.d.ts +0 -59
  172. package/packages/core/dist/intelligence/zettelkasten.js +0 -234
  173. package/packages/core/dist/mcp/custom-tools.d.ts +0 -29
  174. package/packages/core/dist/mcp/custom-tools.js +0 -70
  175. package/packages/core/dist/mcp/index.d.ts +0 -2
  176. package/packages/core/dist/mcp/index.js +0 -2
  177. package/packages/core/dist/mcp/server.d.ts +0 -51
  178. package/packages/core/dist/mcp/server.js +0 -174
  179. package/packages/core/dist/mcp/tools/agentic-graph.d.ts +0 -93
  180. package/packages/core/dist/mcp/tools/agentic-graph.js +0 -116
  181. package/packages/core/dist/mcp/tools/ask.d.ts +0 -29
  182. package/packages/core/dist/mcp/tools/ask.js +0 -43
  183. package/packages/core/dist/mcp/tools/brief.d.ts +0 -31
  184. package/packages/core/dist/mcp/tools/brief.js +0 -39
  185. package/packages/core/dist/mcp/tools/decay.d.ts +0 -33
  186. package/packages/core/dist/mcp/tools/decay.js +0 -32
  187. package/packages/core/dist/mcp/tools/decision-journal.d.ts +0 -78
  188. package/packages/core/dist/mcp/tools/decision-journal.js +0 -79
  189. package/packages/core/dist/mcp/tools/detect-gaps.d.ts +0 -24
  190. package/packages/core/dist/mcp/tools/detect-gaps.js +0 -47
  191. package/packages/core/dist/mcp/tools/export.d.ts +0 -29
  192. package/packages/core/dist/mcp/tools/export.js +0 -60
  193. package/packages/core/dist/mcp/tools/federated-search.d.ts +0 -29
  194. package/packages/core/dist/mcp/tools/federated-search.js +0 -36
  195. package/packages/core/dist/mcp/tools/generate-claude-md.d.ts +0 -35
  196. package/packages/core/dist/mcp/tools/generate-claude-md.js +0 -107
  197. package/packages/core/dist/mcp/tools/generate-draft.d.ts +0 -34
  198. package/packages/core/dist/mcp/tools/generate-draft.js +0 -120
  199. package/packages/core/dist/mcp/tools/get-document.d.ts +0 -35
  200. package/packages/core/dist/mcp/tools/get-document.js +0 -25
  201. package/packages/core/dist/mcp/tools/get-evolution.d.ts +0 -28
  202. package/packages/core/dist/mcp/tools/get-evolution.js +0 -70
  203. package/packages/core/dist/mcp/tools/get-related.d.ts +0 -32
  204. package/packages/core/dist/mcp/tools/get-related.js +0 -33
  205. package/packages/core/dist/mcp/tools/learning-path.d.ts +0 -23
  206. package/packages/core/dist/mcp/tools/learning-path.js +0 -45
  207. package/packages/core/dist/mcp/tools/link-code.d.ts +0 -34
  208. package/packages/core/dist/mcp/tools/link-code.js +0 -44
  209. package/packages/core/dist/mcp/tools/list-topics.d.ts +0 -15
  210. package/packages/core/dist/mcp/tools/list-topics.js +0 -18
  211. package/packages/core/dist/mcp/tools/search.d.ts +0 -39
  212. package/packages/core/dist/mcp/tools/search.js +0 -29
  213. package/packages/core/dist/mcp/tools/snapshot.d.ts +0 -47
  214. package/packages/core/dist/mcp/tools/snapshot.js +0 -84
  215. package/packages/core/dist/multi-vault/index.d.ts +0 -26
  216. package/packages/core/dist/multi-vault/index.js +0 -80
  217. package/packages/core/dist/pack/creator.d.ts +0 -21
  218. package/packages/core/dist/pack/creator.js +0 -105
  219. package/packages/core/dist/pack/exporter.d.ts +0 -4
  220. package/packages/core/dist/pack/exporter.js +0 -18
  221. package/packages/core/dist/pack/importer.d.ts +0 -10
  222. package/packages/core/dist/pack/importer.js +0 -55
  223. package/packages/core/dist/pack/index.d.ts +0 -6
  224. package/packages/core/dist/pack/index.js +0 -5
  225. package/packages/core/dist/pack/marketplace.d.ts +0 -14
  226. package/packages/core/dist/pack/marketplace.js +0 -90
  227. package/packages/core/dist/pack/pii-masker.d.ts +0 -7
  228. package/packages/core/dist/pack/pii-masker.js +0 -29
  229. package/packages/core/dist/pack/types.d.ts +0 -36
  230. package/packages/core/dist/pack/types.js +0 -3
  231. package/packages/core/dist/plugins/index.d.ts +0 -35
  232. package/packages/core/dist/plugins/index.js +0 -57
  233. package/packages/core/dist/plugins/webhooks.d.ts +0 -30
  234. package/packages/core/dist/plugins/webhooks.js +0 -79
  235. package/packages/core/dist/search/adaptive.d.ts +0 -16
  236. package/packages/core/dist/search/adaptive.js +0 -67
  237. package/packages/core/dist/search/bm25.d.ts +0 -4
  238. package/packages/core/dist/search/bm25.js +0 -10
  239. package/packages/core/dist/search/index.d.ts +0 -15
  240. package/packages/core/dist/search/index.js +0 -64
  241. package/packages/core/dist/search/rrf.d.ts +0 -7
  242. package/packages/core/dist/search/rrf.js +0 -21
  243. package/packages/core/dist/search/semantic.d.ts +0 -5
  244. package/packages/core/dist/search/semantic.js +0 -6
  245. package/packages/core/dist/store/index.d.ts +0 -3
  246. package/packages/core/dist/store/index.js +0 -2
  247. package/packages/core/dist/store/sqlite-vec.d.ts +0 -6
  248. package/packages/core/dist/store/sqlite-vec.js +0 -251
  249. package/packages/core/dist/store/types.d.ts +0 -20
  250. package/packages/core/dist/store/types.js +0 -3
  251. package/packages/core/dist/team/index.d.ts +0 -25
  252. package/packages/core/dist/team/index.js +0 -97
  253. package/packages/core/dist/types/chunk.d.ts +0 -23
  254. package/packages/core/dist/types/chunk.js +0 -3
  255. package/packages/core/dist/types/document.d.ts +0 -23
  256. package/packages/core/dist/types/document.js +0 -3
  257. package/packages/core/dist/types/graph.d.ts +0 -39
  258. package/packages/core/dist/types/graph.js +0 -3
  259. package/packages/core/dist/types/index.d.ts +0 -5
  260. package/packages/core/dist/types/index.js +0 -2
  261. package/packages/core/dist/types/search.d.ts +0 -39
  262. package/packages/core/dist/types/search.js +0 -3
  263. package/packages/core/dist/utils/retry.d.ts +0 -25
  264. package/packages/core/dist/utils/retry.js +0 -59
  265. package/packages/core/package.json +0 -67
@@ -1,245 +0,0 @@
1
- // 통합 인제스트 파이프라인
2
- // 어떤 입력이든 → Stellavault 포맷으로 자동 변환 + 분류 + 연결
3
- //
4
- // 지원 입력: URL, PDF 텍스트, 마크다운, 플레인텍스트, YouTube
5
- // 출력: frontmatter 포맷 .md → raw/ → compile → lint
6
- import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
7
- import { join, resolve, basename } from 'node:path';
8
- import { scanFrontmatter, assignIndexCodes, archiveFile } from './zettelkasten.js';
9
- import { compileWiki } from './wiki-compiler.js';
10
- import { autoLink } from './auto-linker.js';
11
- import { DEFAULT_FOLDERS } from '../config.js';
12
- /** HTML 엔티티 디코딩 */
13
- function decodeHtmlEntities(text) {
14
- return text
15
- .replace(/'/g, "'").replace(/'/g, "'")
16
- .replace(/"/g, '"').replace(/&/g, '&')
17
- .replace(/&lt;/g, '<').replace(/&gt;/g, '>')
18
- .replace(/&nbsp;/g, ' ');
19
- }
20
- /** YAML 값에서 위험한 문자를 이스케이프 */
21
- function sanitizeYaml(val) {
22
- return decodeHtmlEntities(val).replace(/["\\]/g, '\\$&').replace(/\n/g, ' ').slice(0, 200);
23
- }
24
- /**
25
- * 어떤 입력이든 Stellavault 표준 포맷으로 변환하여 저장.
26
- */
27
- export function ingest(vaultPath, input, folders = DEFAULT_FOLDERS) {
28
- const stage = input.stage ?? 'fleeting';
29
- const title = decodeHtmlEntities(input.title ?? extractTitleFromContent(input.content, input.type));
30
- const tags = input.tags ?? extractAutoTags(input.content, input.type);
31
- const source = input.source ?? (input.type === 'url' || input.type === 'youtube' ? input.content.split('\n')[0] : 'manual');
32
- // 본문 정리
33
- const body = cleanContent(input.content, input.type);
34
- const wordCount = body.split(/\s+/).length;
35
- // 자동 분류: 길이/구조에 따라 stage 결정
36
- const autoStage = classifyStage(body, stage, wordCount);
37
- // 폴더 결정 (config-driven)
38
- const folderMap = {
39
- fleeting: folders.fleeting,
40
- literature: folders.literature,
41
- permanent: folders.permanent,
42
- };
43
- const folder = folderMap[autoStage];
44
- const dir = resolve(vaultPath, folder);
45
- if (!existsSync(dir))
46
- mkdirSync(dir, { recursive: true });
47
- // 파일명 생성
48
- const now = new Date();
49
- const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, 19);
50
- const slug = title.slice(0, 50).replace(/[^a-zA-Z0-9가-힣\s]/g, '').replace(/\s+/g, '-').toLowerCase();
51
- const filename = `${timestamp}-${slug}.md`;
52
- const filePath = join(folder, filename);
53
- const fullPath = resolve(vaultPath, filePath);
54
- // path traversal 방지
55
- if (!fullPath.startsWith(resolve(vaultPath))) {
56
- throw new Error('Invalid path');
57
- }
58
- // 인덱스 코드 생성 (lazy — 전체 스캔 건너뛸 수 있음)
59
- let indexCode;
60
- try {
61
- // 성능: raw/ 폴더만 스캔 (전체 vault 스캔 대신)
62
- const rawEntries = scanFrontmatter(resolve(vaultPath, folder));
63
- const assignments = assignIndexCodes([...rawEntries, {
64
- filePath, title, tags, connections: [], wordCount,
65
- }]);
66
- indexCode = assignments.get(filePath);
67
- }
68
- catch (err) {
69
- console.warn('[ingest] Index code skipped:', err instanceof Error ? err.message : err);
70
- }
71
- // Stellavault 표준 포맷으로 저장
72
- let md = buildStandardNote({
73
- title,
74
- body,
75
- tags,
76
- stage: autoStage,
77
- source,
78
- indexCode,
79
- created: now.toISOString(),
80
- inputType: input.type,
81
- });
82
- // wikilink 자동 삽입: 기존 노트 제목과 매칭
83
- try {
84
- md = autoLink(md, vaultPath, title, folders);
85
- }
86
- catch (err) {
87
- console.warn('[ingest] Auto-link skipped:', err instanceof Error ? err.message : err);
88
- }
89
- writeFileSync(fullPath, md, 'utf-8');
90
- // 자동 compile: fleeting → wiki (rule-based, <100ms)
91
- try {
92
- const rawDir = resolve(vaultPath, folders.fleeting);
93
- const wikiDir = resolve(vaultPath, folders.wiki);
94
- if (existsSync(rawDir)) {
95
- compileWiki(rawDir, wikiDir);
96
- }
97
- }
98
- catch { /* compile 실패해도 ingest 성공 */ }
99
- return {
100
- savedTo: filePath,
101
- stage: autoStage,
102
- title,
103
- indexCode,
104
- tags,
105
- wordCount,
106
- };
107
- }
108
- /**
109
- * 여러 입력을 배치 처리.
110
- */
111
- export function ingestBatch(vaultPath, inputs) {
112
- return inputs.map(input => ingest(vaultPath, input));
113
- }
114
- /**
115
- * 노트 승격: fleeting → literature → permanent.
116
- * 내용이 충분히 정제되면 다음 단계로 이동.
117
- */
118
- export function promoteNote(vaultPath, filePath, targetStage, folders = DEFAULT_FOLDERS) {
119
- const fullPath = resolve(vaultPath, filePath);
120
- if (!existsSync(fullPath))
121
- throw new Error(`File not found: ${filePath}`);
122
- const content = readFileSync(fullPath, 'utf-8');
123
- // frontmatter의 type 변경
124
- const updated = content.replace(/^type:\s*.+$/m, `type: ${targetStage}`);
125
- // 대상 폴더로 이동 (config-driven)
126
- const folderMap = {
127
- fleeting: folders.fleeting,
128
- literature: folders.literature,
129
- permanent: folders.permanent,
130
- };
131
- const newDir = resolve(vaultPath, folderMap[targetStage]);
132
- if (!existsSync(newDir))
133
- mkdirSync(newDir, { recursive: true });
134
- const newPath = join(folderMap[targetStage], basename(filePath));
135
- const newFullPath = resolve(vaultPath, newPath);
136
- if (!newFullPath.startsWith(resolve(vaultPath))) {
137
- throw new Error('Invalid path');
138
- }
139
- writeFileSync(newFullPath, updated, 'utf-8');
140
- // 원본에 archive 플래그
141
- archiveFile(fullPath);
142
- return newPath;
143
- }
144
- // ─── 내부 헬퍼 ───
145
- function extractTitleFromContent(content, type) {
146
- if (type === 'url' || type === 'youtube') {
147
- // URL에서 도메인 + 경로 추출
148
- try {
149
- const url = new URL(content.split('\n')[0]);
150
- return url.hostname + url.pathname.slice(0, 40);
151
- }
152
- catch {
153
- return 'Untitled Clip';
154
- }
155
- }
156
- // 첫 heading 또는 첫 줄
157
- const heading = content.match(/^#\s+(.+)$/m);
158
- if (heading)
159
- return heading[1];
160
- const firstLine = content.split('\n')[0].trim();
161
- return firstLine.slice(0, 80) || 'Untitled';
162
- }
163
- function extractAutoTags(content, type) {
164
- const tags = new Set();
165
- // 입력 타입 태그
166
- if (type === 'url')
167
- tags.add('web-clip');
168
- if (type === 'youtube')
169
- tags.add('youtube');
170
- if (type === 'pdf-text' || type === 'pdf')
171
- tags.add('pdf');
172
- if (type === 'docx')
173
- tags.add('document');
174
- if (type === 'pptx')
175
- tags.add('presentation');
176
- if (type === 'xlsx' || type === 'xls')
177
- tags.add('spreadsheet');
178
- // 인라인 #태그 추출
179
- const inline = content.match(/#([a-zA-Z가-힣][a-zA-Z0-9가-힣_-]{2,})/g) ?? [];
180
- inline.forEach(t => tags.add(t.slice(1)));
181
- // 스마트 자동 태깅: 문서 내용 분석 → 카테고리 분류
182
- const lc = content.toLowerCase();
183
- if (/회의|meeting|minutes|참석자|agenda/.test(lc))
184
- tags.add('meeting-notes');
185
- if (/기획|prd|요구사항|spec|feature|유저\s*스토리/.test(lc))
186
- tags.add('planning');
187
- if (/api|endpoint|서버|backend|database|쿼리/.test(lc))
188
- tags.add('technical');
189
- if (/디자인|design|ui|ux|figma|wireframe|mockup/.test(lc))
190
- tags.add('design');
191
- if (/논문|paper|abstract|methodology|conclusion|참고문헌/.test(lc))
192
- tags.add('research');
193
- if (/tutorial|강의|강좌|배우|learn|course/.test(lc))
194
- tags.add('learning');
195
- if (/경쟁|competitor|시장|market|swot|분석/.test(lc))
196
- tags.add('analysis');
197
- if (/일기|diary|journal|오늘|today|daily/.test(lc))
198
- tags.add('journal');
199
- return [...tags].slice(0, 15);
200
- }
201
- function cleanContent(content, type) {
202
- if (type === 'url' || type === 'youtube') {
203
- // URL은 첫 줄이 URL, 나머지가 내용
204
- const lines = content.split('\n');
205
- return lines.slice(1).join('\n').trim() || lines[0];
206
- }
207
- return content.trim();
208
- }
209
- function classifyStage(body, requestedStage, wordCount) {
210
- // 요청된 단계가 permanent면 그대로
211
- if (requestedStage === 'permanent')
212
- return 'permanent';
213
- // 자동 분류 기준:
214
- // - 200단어 미만 + 구조 없음 → fleeting
215
- // - 200-1000단어 + 출처 있음 → literature
216
- // - 1000단어+ + 구조 있음 → permanent 후보 (but 수동 승격 권장)
217
- if (wordCount < 200 && !body.includes('## '))
218
- return 'fleeting';
219
- if (wordCount >= 200 && (body.includes('## ') || body.includes('> ')))
220
- return 'literature';
221
- return requestedStage;
222
- }
223
- function buildStandardNote(params) {
224
- const lines = [
225
- '---',
226
- `title: "${sanitizeYaml(params.title)}"`,
227
- `type: ${params.stage}`,
228
- `source: "${sanitizeYaml(params.source)}"`,
229
- `input_type: ${params.inputType}`,
230
- params.indexCode ? `zettel_id: "${params.indexCode}"` : null,
231
- `tags: [${params.tags.map(t => `"${sanitizeYaml(t)}"`).join(', ')}]`,
232
- `created: ${params.created}`,
233
- `summary: "${sanitizeYaml(params.body.slice(0, 100))}"`,
234
- '---',
235
- '',
236
- `# ${params.title}`,
237
- '',
238
- params.body,
239
- '',
240
- '---',
241
- `*Ingested via \`stellavault ingest\` (${params.inputType}) at ${params.created}*`,
242
- ];
243
- return lines.filter(l => l !== null).join('\n');
244
- }
245
- //# sourceMappingURL=ingest-pipeline.js.map
@@ -1,27 +0,0 @@
1
- import type { VectorStore } from '../store/types.js';
2
- export interface LintResult {
3
- score: number;
4
- issues: LintIssue[];
5
- suggestions: string[];
6
- stats: {
7
- totalDocs: number;
8
- gaps: number;
9
- duplicates: number;
10
- contradictions: number;
11
- isolatedNodes: number;
12
- orphanTags: number;
13
- };
14
- }
15
- export interface LintIssue {
16
- type: 'gap' | 'duplicate' | 'contradiction' | 'isolated' | 'stale' | 'empty';
17
- severity: 'critical' | 'warning' | 'info';
18
- message: string;
19
- filePath?: string;
20
- suggestion?: string;
21
- }
22
- /**
23
- * vault 전체를 스캔하여 지식 건강도를 평가.
24
- * 기존 gap-detector, duplicate-detector, contradiction-detector를 통합.
25
- */
26
- export declare function lintKnowledge(store: VectorStore): Promise<LintResult>;
27
- //# sourceMappingURL=knowledge-lint.d.ts.map
@@ -1,132 +0,0 @@
1
- // Feature: stellavault lint — 자동 지식 건강 검사
2
- // 불일치, 누락, 연결 제안, 고립 노드 등을 종합 리포트
3
- import { detectKnowledgeGaps } from './gap-detector.js';
4
- import { detectDuplicates } from './duplicate-detector.js';
5
- import { detectContradictions } from './contradiction-detector.js';
6
- /**
7
- * vault 전체를 스캔하여 지식 건강도를 평가.
8
- * 기존 gap-detector, duplicate-detector, contradiction-detector를 통합.
9
- */
10
- export async function lintKnowledge(store) {
11
- const issues = [];
12
- const suggestions = [];
13
- const docs = await store.getAllDocuments();
14
- const totalDocs = docs.length;
15
- // 1. 갭 탐지
16
- let gapCount = 0;
17
- let isolatedCount = 0;
18
- try {
19
- const gapReport = await detectKnowledgeGaps(store);
20
- gapCount = gapReport.totalGaps;
21
- isolatedCount = gapReport.isolatedNodes.length;
22
- for (const gap of gapReport.gaps.filter(g => g.severity !== 'low')) {
23
- issues.push({
24
- type: 'gap',
25
- severity: gap.severity === 'high' ? 'critical' : 'warning',
26
- message: `Knowledge gap: ${gap.clusterA} ↔ ${gap.clusterB} (${gap.bridgeCount} connections)`,
27
- suggestion: gap.suggestedTopic,
28
- });
29
- }
30
- for (const node of gapReport.isolatedNodes.slice(0, 10)) {
31
- issues.push({
32
- type: 'isolated',
33
- severity: 'warning',
34
- message: `Isolated note: "${node.title}" (${node.connections} connections)`,
35
- filePath: node.id,
36
- suggestion: 'Add links to related topics or tags to integrate this note.',
37
- });
38
- }
39
- }
40
- catch (err) {
41
- console.error('[lint] Gap detection failed:', err instanceof Error ? err.message : err);
42
- }
43
- // 2. 중복 탐지
44
- let dupCount = 0;
45
- try {
46
- const dups = await detectDuplicates(store, 0.88, 10);
47
- dupCount = dups.length;
48
- for (const dup of dups) {
49
- issues.push({
50
- type: 'duplicate',
51
- severity: 'warning',
52
- message: `Possible duplicate: "${dup.docA.title}" ≈ "${dup.docB.title}" (${Math.round(dup.similarity * 100)}%)`,
53
- suggestion: 'Consider merging these notes.',
54
- });
55
- }
56
- }
57
- catch (err) {
58
- console.error('[lint] Detection failed:', err instanceof Error ? err.message : err);
59
- }
60
- // 3. 모순 탐지
61
- let contradictionCount = 0;
62
- try {
63
- const contradictions = await detectContradictions(store, 5);
64
- contradictionCount = contradictions.length;
65
- for (const c of contradictions) {
66
- issues.push({
67
- type: 'contradiction',
68
- severity: 'warning',
69
- message: `Potential contradiction: "${c.docA.title}" vs "${c.docB.title}"`,
70
- suggestion: 'Review these documents for conflicting information.',
71
- });
72
- }
73
- }
74
- catch (err) {
75
- console.error('[lint] Detection failed:', err instanceof Error ? err.message : err);
76
- }
77
- // 4. 빈 문서 / 매우 짧은 문서
78
- for (const doc of docs) {
79
- if (doc.content.trim().length < 50) {
80
- issues.push({
81
- type: 'empty',
82
- severity: 'info',
83
- message: `Very short note: "${doc.title}" (${doc.content.trim().length} chars)`,
84
- filePath: doc.filePath,
85
- suggestion: 'Consider expanding or removing this note.',
86
- });
87
- }
88
- }
89
- // 5. 오래된 문서 (180일 이상 미수정)
90
- const now = Date.now();
91
- const staleDocs = docs.filter(d => {
92
- if (!d.lastModified)
93
- return false;
94
- const age = (now - new Date(d.lastModified).getTime()) / 86400000;
95
- return age > 180;
96
- });
97
- if (staleDocs.length > totalDocs * 0.3) {
98
- suggestions.push(`${staleDocs.length} documents haven't been modified in 6+ months. Run \`stellavault decay\` to review.`);
99
- }
100
- // 6. 건강도 점수 계산
101
- const criticalCount = issues.filter(i => i.severity === 'critical').length;
102
- const warningCount = issues.filter(i => i.severity === 'warning').length;
103
- const penalty = criticalCount * 10 + warningCount * 3;
104
- const score = Math.max(0, Math.min(100, 100 - penalty));
105
- // 7. 종합 제안
106
- if (gapCount > 5) {
107
- suggestions.push(`${gapCount} knowledge gaps found. Start filling the most critical ones.`);
108
- }
109
- if (dupCount > 3) {
110
- suggestions.push(`${dupCount} duplicate documents detected. Run \`stellavault duplicates\` to merge.`);
111
- }
112
- if (isolatedCount > 10) {
113
- suggestions.push(`${isolatedCount} isolated notes found. Add tags or links to connect them.`);
114
- }
115
- if (totalDocs > 0 && issues.length === 0) {
116
- suggestions.push('Your knowledge base is healthy! Keep it up.');
117
- }
118
- return {
119
- score,
120
- issues,
121
- suggestions,
122
- stats: {
123
- totalDocs,
124
- gaps: gapCount,
125
- duplicates: dupCount,
126
- contradictions: contradictionCount,
127
- isolatedNodes: isolatedCount,
128
- orphanTags: 0,
129
- },
130
- };
131
- }
132
- //# sourceMappingURL=knowledge-lint.js.map
@@ -1,31 +0,0 @@
1
- import type { DecayReport } from './types.js';
2
- export interface LearningItem {
3
- documentId: string;
4
- title: string;
5
- reason: string;
6
- priority: 'critical' | 'important' | 'suggested';
7
- score: number;
8
- category: 'review' | 'explore' | 'bridge';
9
- }
10
- export interface LearningPath {
11
- items: LearningItem[];
12
- summary: {
13
- reviewCount: number;
14
- exploreCount: number;
15
- bridgeCount: number;
16
- estimatedMinutes: number;
17
- };
18
- generatedAt: string;
19
- }
20
- export interface LearningPathInput {
21
- decayReport: DecayReport;
22
- gaps?: Array<{
23
- clusterA: string;
24
- clusterB: string;
25
- severity: string;
26
- suggestedTopic: string;
27
- }>;
28
- recentSearches?: string[];
29
- }
30
- export declare function generateLearningPath(input: LearningPathInput, limit?: number): LearningPath;
31
- //# sourceMappingURL=learning-path.d.ts.map
@@ -1,53 +0,0 @@
1
- // AI Learning Path Generator (F-A11)
2
- // Analyzes decay + gaps + relationships to recommend what to review/learn next
3
- export function generateLearningPath(input, limit = 15) {
4
- const items = [];
5
- // 1. Review: decaying notes (highest priority)
6
- if (input.decayReport.topDecaying) {
7
- for (const d of input.decayReport.topDecaying) {
8
- const r = d.retrievability ?? 0;
9
- const urgency = (1 - r) * 100;
10
- items.push({
11
- documentId: d.documentId,
12
- title: d.title,
13
- reason: r < 0.3
14
- ? `Critical: ${Math.round(r * 100)}% retrievability, ${d.daysSinceAccess}d since last access`
15
- : `Fading: ${Math.round(r * 100)}% retrievability, review to strengthen memory`,
16
- priority: r < 0.3 ? 'critical' : r < 0.5 ? 'important' : 'suggested',
17
- score: Math.round(urgency),
18
- category: 'review',
19
- });
20
- }
21
- }
22
- // 2. Bridge: knowledge gaps
23
- if (input.gaps) {
24
- for (const gap of input.gaps) {
25
- const severityScore = gap.severity === 'high' ? 80 : gap.severity === 'medium' ? 60 : 40;
26
- items.push({
27
- documentId: '',
28
- title: gap.suggestedTopic || `${gap.clusterA} × ${gap.clusterB}`,
29
- reason: `Gap between "${gap.clusterA}" and "${gap.clusterB}" — creating a bridge note strengthens your knowledge network`,
30
- priority: gap.severity === 'high' ? 'important' : 'suggested',
31
- score: severityScore,
32
- category: 'bridge',
33
- });
34
- }
35
- }
36
- // Sort by score descending
37
- items.sort((a, b) => b.score - a.score);
38
- const selected = items.slice(0, limit);
39
- const reviewCount = selected.filter(i => i.category === 'review').length;
40
- const exploreCount = selected.filter(i => i.category === 'explore').length;
41
- const bridgeCount = selected.filter(i => i.category === 'bridge').length;
42
- return {
43
- items: selected,
44
- summary: {
45
- reviewCount,
46
- exploreCount,
47
- bridgeCount,
48
- estimatedMinutes: reviewCount * 3 + exploreCount * 5 + bridgeCount * 8,
49
- },
50
- generatedAt: new Date().toISOString(),
51
- };
52
- }
53
- //# sourceMappingURL=learning-path.js.map
@@ -1,31 +0,0 @@
1
- import type { DecayReport } from './types.js';
2
- export interface NotificationConfig {
3
- decay: {
4
- enabled: boolean;
5
- criticalThreshold: number;
6
- warningThreshold: number;
7
- };
8
- gaps: {
9
- enabled: boolean;
10
- minSeverity: 'low' | 'medium' | 'high';
11
- };
12
- digest: {
13
- enabled: boolean;
14
- frequency: 'daily' | 'weekly' | 'off';
15
- };
16
- }
17
- export interface Notification {
18
- id: string;
19
- type: 'decay_critical' | 'decay_warning' | 'gap_detected' | 'digest';
20
- title: string;
21
- message: string;
22
- timestamp: string;
23
- priority: 'high' | 'medium' | 'low';
24
- data?: Record<string, unknown>;
25
- }
26
- export declare function checkNotifications(decayReport: DecayReport, gaps: Array<{
27
- severity: string;
28
- clusterA: string;
29
- clusterB: string;
30
- }>, config?: Partial<NotificationConfig>): Notification[];
31
- //# sourceMappingURL=notifications.d.ts.map
@@ -1,65 +0,0 @@
1
- // Notification Center (F-A05)
2
- // Configurable alerts for decay thresholds, gap detection, weekly digest
3
- const DEFAULT_CONFIG = {
4
- decay: { enabled: true, criticalThreshold: 0.3, warningThreshold: 0.5 },
5
- gaps: { enabled: true, minSeverity: 'medium' },
6
- digest: { enabled: true, frequency: 'weekly' },
7
- };
8
- export function checkNotifications(decayReport, gaps, config = {}) {
9
- const cfg = {
10
- decay: { ...DEFAULT_CONFIG.decay, ...config.decay },
11
- gaps: { ...DEFAULT_CONFIG.gaps, ...config.gaps },
12
- digest: { ...DEFAULT_CONFIG.digest, ...config.digest },
13
- };
14
- const notifications = [];
15
- const now = new Date().toISOString();
16
- // Decay alerts
17
- if (cfg.decay.enabled && decayReport.topDecaying) {
18
- const criticals = decayReport.topDecaying.filter(d => d.retrievability < cfg.decay.criticalThreshold);
19
- const warnings = decayReport.topDecaying.filter(d => d.retrievability >= cfg.decay.criticalThreshold && d.retrievability < cfg.decay.warningThreshold);
20
- if (criticals.length > 0) {
21
- notifications.push({
22
- id: `decay-critical-${Date.now()}`,
23
- type: 'decay_critical',
24
- title: `${criticals.length} notes critically fading`,
25
- message: criticals.slice(0, 3).map(d => `"${d.title}" (${Math.round(d.retrievability * 100)}%)`).join(', '),
26
- timestamp: now,
27
- priority: 'high',
28
- data: { count: criticals.length, notes: criticals.slice(0, 5).map(d => d.title) },
29
- });
30
- }
31
- if (warnings.length > 0) {
32
- notifications.push({
33
- id: `decay-warning-${Date.now()}`,
34
- type: 'decay_warning',
35
- title: `${warnings.length} notes starting to fade`,
36
- message: `Average retrievability: ${Math.round(decayReport.averageR * 100)}%`,
37
- timestamp: now,
38
- priority: 'medium',
39
- data: { count: warnings.length },
40
- });
41
- }
42
- }
43
- // Gap alerts
44
- if (cfg.gaps.enabled) {
45
- const severityOrder = { high: 3, medium: 2, low: 1 };
46
- const minLevel = severityOrder[cfg.gaps.minSeverity] ?? 2;
47
- const significantGaps = gaps.filter(g => (severityOrder[g.severity] ?? 0) >= minLevel);
48
- if (significantGaps.length > 0) {
49
- notifications.push({
50
- id: `gap-${Date.now()}`,
51
- type: 'gap_detected',
52
- title: `${significantGaps.length} knowledge gaps detected`,
53
- message: significantGaps.slice(0, 2).map(g => `${g.clusterA} ↔ ${g.clusterB}`).join(', '),
54
- timestamp: now,
55
- priority: significantGaps.some(g => g.severity === 'high') ? 'high' : 'medium',
56
- data: { count: significantGaps.length },
57
- });
58
- }
59
- }
60
- return notifications.sort((a, b) => {
61
- const p = { high: 3, medium: 2, low: 1 };
62
- return (p[b.priority] ?? 0) - (p[a.priority] ?? 0);
63
- });
64
- }
65
- //# sourceMappingURL=notifications.js.map
@@ -1,14 +0,0 @@
1
- import type { VectorStore } from '../store/types.js';
2
- export interface PredictedGap {
3
- topic: string;
4
- reason: string;
5
- confidence: number;
6
- relatedTopics: string[];
7
- category: 'adjacent' | 'bridging' | 'deepening';
8
- }
9
- /**
10
- * Analyze graph topology to predict knowledge worth acquiring.
11
- * Uses degree centrality, cluster density, and tag co-occurrence.
12
- */
13
- export declare function predictKnowledgeGaps(store: VectorStore, limit?: number): Promise<PredictedGap[]>;
14
- //# sourceMappingURL=predictive-gaps.d.ts.map
@@ -1,74 +0,0 @@
1
- // Predictive Gap Analysis (F-A14)
2
- // Based on graph topology, predict knowledge areas worth exploring
3
- /**
4
- * Analyze graph topology to predict knowledge worth acquiring.
5
- * Uses degree centrality, cluster density, and tag co-occurrence.
6
- */
7
- export async function predictKnowledgeGaps(store, limit = 10) {
8
- const docs = await store.getAllDocuments();
9
- const topics = await store.getTopics();
10
- if (docs.length < 10)
11
- return [];
12
- const predictions = [];
13
- // 1. Find isolated tags (topics that appear rarely and could be expanded)
14
- const topicCounts = new Map(topics.map(t => [t.topic, t.count]));
15
- const avgCount = topics.reduce((s, t) => s + t.count, 0) / (topics.length || 1);
16
- // Tags that appear 1-2 times — potential deepening opportunities
17
- const sparseTopics = topics.filter(t => t.count <= 2 && t.count > 0);
18
- for (const t of sparseTopics.slice(0, 5)) {
19
- predictions.push({
20
- topic: t.topic,
21
- reason: `Only ${t.count} note(s) on "${t.topic}" — deepening this area would strengthen your knowledge network`,
22
- confidence: 0.6,
23
- relatedTopics: findCoOccurring(t.topic, docs),
24
- category: 'deepening',
25
- });
26
- }
27
- // 2. Find tag pairs that never co-occur but are both frequent
28
- const frequentTopics = topics.filter(t => t.count >= avgCount).slice(0, 20);
29
- const coOccurrence = new Map();
30
- for (const doc of docs) {
31
- for (const tagA of doc.tags) {
32
- if (!coOccurrence.has(tagA))
33
- coOccurrence.set(tagA, new Set());
34
- for (const tagB of doc.tags) {
35
- if (tagA !== tagB)
36
- coOccurrence.get(tagA).add(tagB);
37
- }
38
- }
39
- }
40
- for (let i = 0; i < frequentTopics.length; i++) {
41
- for (let j = i + 1; j < frequentTopics.length; j++) {
42
- const a = frequentTopics[i].topic;
43
- const b = frequentTopics[j].topic;
44
- const aCoOccurs = coOccurrence.get(a) ?? new Set();
45
- if (!aCoOccurs.has(b)) {
46
- predictions.push({
47
- topic: `${a} × ${b}`,
48
- reason: `"${a}" (${frequentTopics[i].count} notes) and "${b}" (${frequentTopics[j].count} notes) are both well-known but never connected — bridging them could reveal insights`,
49
- confidence: 0.7,
50
- relatedTopics: [a, b],
51
- category: 'bridging',
52
- });
53
- }
54
- }
55
- }
56
- // 3. Adjacent topics — topics that co-occur with many of your topics but you don't have
57
- // (This would ideally use external knowledge, but we approximate with tag patterns)
58
- return predictions
59
- .sort((a, b) => b.confidence - a.confidence)
60
- .slice(0, limit);
61
- }
62
- function findCoOccurring(topic, docs) {
63
- const coTopics = new Map();
64
- for (const doc of docs) {
65
- if (doc.tags.includes(topic)) {
66
- for (const t of doc.tags) {
67
- if (t !== topic)
68
- coTopics.set(t, (coTopics.get(t) ?? 0) + 1);
69
- }
70
- }
71
- }
72
- return [...coTopics.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([t]) => t);
73
- }
74
- //# sourceMappingURL=predictive-gaps.js.map