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,24 +0,0 @@
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
@@ -1,135 +0,0 @@
1
- // Voice Knowledge Capture (P3-F25)
2
- // 음성 파일 → 텍스트 → 자동 분류 → vault 저장 → 인덱싱
3
- import { execFileSync, execSync } from 'node:child_process';
4
- import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
5
- import { join, basename } from 'node:path';
6
- // CRIT-03: 화이트리스트 검증
7
- const ALLOWED_MODELS = ['tiny', 'base', 'small', 'medium', 'large'];
8
- const ALLOWED_LANGUAGES = ['auto', 'en', 'ko', 'ja', 'zh', 'es', 'fr', 'de', 'it', 'pt', 'ru', 'ar', 'hi'];
9
- function validateModel(model) {
10
- if (!ALLOWED_MODELS.includes(model))
11
- throw new Error(`Invalid model: ${model}. Allowed: ${ALLOWED_MODELS.join(', ')}`);
12
- return model;
13
- }
14
- function validateLanguage(lang) {
15
- if (!ALLOWED_LANGUAGES.includes(lang))
16
- throw new Error(`Invalid language: ${lang}. Allowed: ${ALLOWED_LANGUAGES.join(', ')}`);
17
- return lang;
18
- }
19
- // Whisper CLI가 설치되어 있는지 확인
20
- export function isWhisperAvailable() {
21
- try {
22
- execSync('whisper --help', { stdio: 'ignore' });
23
- return true;
24
- }
25
- catch {
26
- return false;
27
- }
28
- }
29
- // 음성 파일 → 텍스트 변환 (Whisper CLI)
30
- export async function transcribeAudio(audioPath, options = {}) {
31
- const { model = 'base', language } = options;
32
- if (!existsSync(audioPath)) {
33
- throw new Error(`Audio file not found: ${audioPath}`);
34
- }
35
- // CRIT-03 fix: execFileSync + 화이트리스트 검증 (command injection 방지)
36
- if (isWhisperAvailable()) {
37
- const safeModel = validateModel(model);
38
- const args = [audioPath, '--model', safeModel, '--output_format', 'txt', '--output_dir', '/tmp/sv-whisper'];
39
- if (language)
40
- args.push('--language', validateLanguage(language));
41
- mkdirSync('/tmp/sv-whisper', { recursive: true });
42
- try {
43
- execFileSync('whisper', args, { stdio: 'pipe', timeout: 300000 });
44
- const outputName = basename(audioPath).replace(/\.[^.]+$/, '.txt');
45
- const { readFileSync } = await import('node:fs');
46
- return readFileSync(join('/tmp/sv-whisper', outputName), 'utf-8').trim();
47
- }
48
- catch (err) {
49
- throw new Error(`Whisper failed: ${err instanceof Error ? err.message : err}`);
50
- }
51
- }
52
- // Whisper 없으면 에러
53
- throw new Error('Whisper not installed. Install: pip install openai-whisper');
54
- }
55
- // 트랜스크립트에서 자동 태그 추출 (간단한 키워드 매칭)
56
- function autoTag(text) {
57
- const tags = [];
58
- const lower = text.toLowerCase();
59
- const keywords = {
60
- 'meeting': ['meeting', 'discuss', '미팅', '회의'],
61
- 'decision': ['decide', 'agreed', '결정', '합의'],
62
- 'idea': ['idea', 'thought', '아이디어', '생각'],
63
- 'todo': ['todo', 'task', 'action item', '할 일'],
64
- 'bug': ['bug', 'error', 'fix', '버그', '에러'],
65
- 'architecture': ['architecture', 'design', 'system', '아키텍처', '설계'],
66
- };
67
- for (const [tag, words] of Object.entries(keywords)) {
68
- if (words.some(w => lower.includes(w)))
69
- tags.push(tag);
70
- }
71
- return tags;
72
- }
73
- // 음성 → vault 노트 생성
74
- export async function captureVoice(audioPath, options) {
75
- const { vaultPath, folder = '01_Knowledge/voice', type = 'note', tags: userTags = [] } = options;
76
- try {
77
- // 1. 음성→텍스트
78
- const transcript = await transcribeAudio(audioPath, {
79
- model: options.model,
80
- language: options.language,
81
- });
82
- if (!transcript) {
83
- return { title: '', filePath: '', transcript: '', tags: [], success: false, error: 'Empty transcript' };
84
- }
85
- // 2. 제목 생성 (첫 문장 또는 첫 30자)
86
- const firstLine = transcript.split(/[.\n!?]/)[0]?.trim() || transcript.slice(0, 30);
87
- const title = firstLine.slice(0, 60);
88
- const safeTitle = title.replace(/[<>:"/\\|?*]/g, '').replace(/\s+/g, ' ').trim();
89
- // 3. 자동 태그
90
- const autoTags = autoTag(transcript);
91
- const allTags = [...new Set([...userTags, ...autoTags, 'voice'])];
92
- // 4. frontmatter + 마크다운 생성
93
- const date = new Date().toISOString();
94
- const content = [
95
- '---',
96
- `title: "${safeTitle}"`,
97
- `source: voice`,
98
- `type: ${type}`,
99
- `tags: [${allTags.map(t => `"${t}"`).join(', ')}]`,
100
- `captured: ${date}`,
101
- `audio: ${basename(audioPath)}`,
102
- '---',
103
- '',
104
- `# ${safeTitle}`,
105
- '',
106
- `> Voice capture: ${date.slice(0, 10)}`,
107
- '',
108
- transcript,
109
- '',
110
- ].join('\n');
111
- // 5. vault에 저장
112
- const dir = join(vaultPath, folder);
113
- mkdirSync(dir, { recursive: true });
114
- const filePath = join(dir, `${date.slice(0, 10)} ${safeTitle}.md`);
115
- writeFileSync(filePath, content, 'utf-8');
116
- return {
117
- title: safeTitle,
118
- filePath,
119
- transcript,
120
- tags: allTags,
121
- success: true,
122
- };
123
- }
124
- catch (err) {
125
- return {
126
- title: '',
127
- filePath: '',
128
- transcript: '',
129
- tags: [],
130
- success: false,
131
- error: err instanceof Error ? err.message : String(err),
132
- };
133
- }
134
- }
135
- //# sourceMappingURL=voice.js.map
@@ -1,3 +0,0 @@
1
- export { syncToCloud, restoreFromCloud, getSyncState, encrypt, decrypt, getOrCreateEncryptionKey } from './sync.js';
2
- export type { CloudConfig, SyncResult } from './sync.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +0,0 @@
1
- export { syncToCloud, restoreFromCloud, getSyncState, encrypt, decrypt, getOrCreateEncryptionKey } from './sync.js';
2
- //# sourceMappingURL=index.js.map
@@ -1,29 +0,0 @@
1
- export interface CloudConfig {
2
- endpoint: string;
3
- bucket: string;
4
- accessKeyId: string;
5
- secretAccessKey: string;
6
- encryptionKey?: string;
7
- }
8
- export interface SyncResult {
9
- action: 'upload' | 'download';
10
- dbSize: number;
11
- encryptedSize: number;
12
- timestamp: string;
13
- success: boolean;
14
- error?: string;
15
- }
16
- export declare function encrypt(data: Buffer, key: Buffer): {
17
- encrypted: Buffer;
18
- iv: Buffer;
19
- tag: Buffer;
20
- };
21
- export declare function decrypt(encrypted: Buffer, key: Buffer, iv: Buffer, tag: Buffer): Buffer;
22
- export declare function getOrCreateEncryptionKey(userKey?: string): Buffer;
23
- export declare function syncToCloud(dbPath: string, config: CloudConfig): Promise<SyncResult>;
24
- export declare function restoreFromCloud(dbPath: string, config: CloudConfig): Promise<SyncResult>;
25
- export declare function getSyncState(): {
26
- lastSync: string;
27
- dbSize: number;
28
- } | null;
29
- //# sourceMappingURL=sync.d.ts.map
@@ -1,137 +0,0 @@
1
- // Cloud Sync (F-A04) — E2E encrypted SQLite backup
2
- // 서버리스: S3-compatible API로 직접 업로드 (R2, S3, MinIO)
3
- // Design Ref: PRD §7.1 Tier 2
4
- import { createCipheriv, createDecipheriv, randomBytes, createHash } from 'node:crypto';
5
- import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'node:fs';
6
- import { join } from 'node:path';
7
- import { homedir } from 'node:os';
8
- const CLOUD_DIR = join(homedir(), '.stellavault', 'cloud');
9
- const KEY_FILE = join(CLOUD_DIR, 'encryption.key');
10
- const SYNC_STATE_FILE = join(CLOUD_DIR, 'sync-state.json');
11
- // AES-256-GCM 암호화
12
- export function encrypt(data, key) {
13
- const iv = randomBytes(16);
14
- const cipher = createCipheriv('aes-256-gcm', key, iv);
15
- const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
16
- const tag = cipher.getAuthTag();
17
- return { encrypted, iv, tag };
18
- }
19
- export function decrypt(encrypted, key, iv, tag) {
20
- const decipher = createDecipheriv('aes-256-gcm', key, iv);
21
- decipher.setAuthTag(tag);
22
- return Buffer.concat([decipher.update(encrypted), decipher.final()]);
23
- }
24
- // 암호화 키 관리
25
- export function getOrCreateEncryptionKey(userKey) {
26
- mkdirSync(CLOUD_DIR, { recursive: true });
27
- if (userKey) {
28
- const key = createHash('sha256').update(userKey).digest();
29
- writeFileSync(KEY_FILE, key.toString('hex'), 'utf-8');
30
- return key;
31
- }
32
- if (existsSync(KEY_FILE)) {
33
- return Buffer.from(readFileSync(KEY_FILE, 'utf-8').trim(), 'hex');
34
- }
35
- const key = randomBytes(32);
36
- writeFileSync(KEY_FILE, key.toString('hex'), { encoding: 'utf-8', mode: 0o600 });
37
- try {
38
- chmodSync(KEY_FILE, 0o600);
39
- }
40
- catch { /* Windows may not support */ }
41
- return key;
42
- }
43
- // S3-compatible upload (presigned 불필요 — 직접 PUT)
44
- async function s3Put(config, objectKey, data, contentType = 'application/octet-stream') {
45
- const { endpoint, bucket, accessKeyId, secretAccessKey } = config;
46
- // HIGH-05: endpoint 검증
47
- try {
48
- const parsed = new URL(endpoint);
49
- if (!['http:', 'https:'].includes(parsed.protocol))
50
- throw new Error('Invalid protocol');
51
- if (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1')
52
- throw new Error('Local endpoint');
53
- }
54
- catch (e) {
55
- throw new Error(`Invalid cloud endpoint: ${endpoint}. ${e instanceof Error ? e.message : ''}`);
56
- }
57
- const url = `${endpoint}/${bucket}/${objectKey}`;
58
- const date = new Date().toISOString().replace(/[-:]/g, '').slice(0, 15) + 'Z';
59
- const res = await fetch(url, {
60
- method: 'PUT',
61
- headers: {
62
- 'Content-Type': contentType,
63
- 'Content-Length': String(data.length),
64
- 'x-amz-date': date,
65
- 'x-amz-content-sha256': createHash('sha256').update(data).digest('hex'),
66
- // R2는 Bearer token 지원
67
- 'Authorization': `Bearer ${secretAccessKey}`,
68
- },
69
- body: data,
70
- });
71
- return res.ok;
72
- }
73
- async function s3Get(config, objectKey) {
74
- const url = `${config.endpoint}/${config.bucket}/${objectKey}`;
75
- const res = await fetch(url, {
76
- headers: { 'Authorization': `Bearer ${config.secretAccessKey}` },
77
- });
78
- if (!res.ok)
79
- return null;
80
- return Buffer.from(await res.arrayBuffer());
81
- }
82
- // Sync: 로컬 DB → 암호화 → 업로드
83
- export async function syncToCloud(dbPath, config) {
84
- const timestamp = new Date().toISOString();
85
- try {
86
- if (!existsSync(dbPath)) {
87
- return { action: 'upload', dbSize: 0, encryptedSize: 0, timestamp, success: false, error: 'DB not found' };
88
- }
89
- const dbData = readFileSync(dbPath);
90
- const key = getOrCreateEncryptionKey(config.encryptionKey);
91
- const { encrypted, iv, tag } = encrypt(dbData, key);
92
- // 패키징: [iv(16)] + [tag(16)] + [encrypted data]
93
- const payload = Buffer.concat([iv, tag, encrypted]);
94
- const objectKey = `stellavault/index.db.enc`;
95
- const success = await s3Put(config, objectKey, payload);
96
- // 동기화 상태 저장
97
- const state = { lastSync: timestamp, dbSize: dbData.length, encryptedSize: payload.length, objectKey };
98
- mkdirSync(CLOUD_DIR, { recursive: true });
99
- writeFileSync(SYNC_STATE_FILE, JSON.stringify(state, null, 2), 'utf-8');
100
- return { action: 'upload', dbSize: dbData.length, encryptedSize: payload.length, timestamp, success };
101
- }
102
- catch (err) {
103
- return { action: 'upload', dbSize: 0, encryptedSize: 0, timestamp, success: false, error: err instanceof Error ? err.message : String(err) };
104
- }
105
- }
106
- // Restore: 다운로드 → 복호화 → 로컬 DB 덮어쓰기
107
- export async function restoreFromCloud(dbPath, config) {
108
- const timestamp = new Date().toISOString();
109
- try {
110
- const objectKey = `stellavault/index.db.enc`;
111
- const payload = await s3Get(config, objectKey);
112
- if (!payload) {
113
- return { action: 'download', dbSize: 0, encryptedSize: 0, timestamp, success: false, error: 'No backup found in cloud' };
114
- }
115
- const key = getOrCreateEncryptionKey(config.encryptionKey);
116
- const iv = payload.subarray(0, 16);
117
- const tag = payload.subarray(16, 32);
118
- const encrypted = payload.subarray(32);
119
- const dbData = decrypt(encrypted, key, iv, tag);
120
- // 백업 후 덮어쓰기
121
- if (existsSync(dbPath)) {
122
- writeFileSync(dbPath + '.backup', readFileSync(dbPath));
123
- }
124
- writeFileSync(dbPath, dbData);
125
- return { action: 'download', dbSize: dbData.length, encryptedSize: payload.length, timestamp, success: true };
126
- }
127
- catch (err) {
128
- return { action: 'download', dbSize: 0, encryptedSize: 0, timestamp, success: false, error: err instanceof Error ? err.message : String(err) };
129
- }
130
- }
131
- // 동기화 상태 조회
132
- export function getSyncState() {
133
- if (!existsSync(SYNC_STATE_FILE))
134
- return null;
135
- return JSON.parse(readFileSync(SYNC_STATE_FILE, 'utf-8'));
136
- }
137
- //# sourceMappingURL=sync.js.map
@@ -1,35 +0,0 @@
1
- export interface FolderNames {
2
- fleeting: string;
3
- literature: string;
4
- permanent: string;
5
- wiki: string;
6
- }
7
- export interface StellavaultConfig {
8
- vaultPath: string;
9
- dbPath: string;
10
- folders: FolderNames;
11
- embedding: {
12
- model: 'local' | 'openai';
13
- localModel: string;
14
- };
15
- chunking: {
16
- maxTokens: number;
17
- overlap: number;
18
- minTokens: number;
19
- };
20
- search: {
21
- defaultLimit: number;
22
- rrfK: number;
23
- };
24
- mcp: {
25
- mode: 'stdio' | 'sse';
26
- port: number;
27
- };
28
- }
29
- export declare const DEFAULT_FOLDERS: FolderNames;
30
- /**
31
- * .stellavault.json 파일을 찾아 로드합니다.
32
- * 탐색 순서: cwd → home directory → defaults
33
- */
34
- export declare function loadConfig(configPath?: string): StellavaultConfig;
35
- //# sourceMappingURL=config.d.ts.map
@@ -1,63 +0,0 @@
1
- // Design Ref: §10.2 — 설정 파일 구조 (.stellavault.json 로더)
2
- import { readFileSync, existsSync } from 'node:fs';
3
- import { resolve, join } from 'node:path';
4
- import { homedir } from 'node:os';
5
- export const DEFAULT_FOLDERS = {
6
- fleeting: 'raw',
7
- literature: '_literature',
8
- permanent: '_permanent',
9
- wiki: '_wiki',
10
- };
11
- const DEFAULT_CONFIG = {
12
- vaultPath: '',
13
- dbPath: join(homedir(), '.stellavault', 'index.db'),
14
- folders: { ...DEFAULT_FOLDERS },
15
- embedding: {
16
- model: 'local',
17
- localModel: 'paraphrase-multilingual-MiniLM-L12-v2',
18
- },
19
- chunking: {
20
- maxTokens: 300,
21
- overlap: 50,
22
- minTokens: 50,
23
- },
24
- search: {
25
- defaultLimit: 10,
26
- rrfK: 60,
27
- },
28
- mcp: {
29
- mode: 'stdio',
30
- port: 3333,
31
- },
32
- };
33
- /**
34
- * .stellavault.json 파일을 찾아 로드합니다.
35
- * 탐색 순서: cwd → home directory → defaults
36
- */
37
- export function loadConfig(configPath) {
38
- const paths = configPath
39
- ? [resolve(configPath)]
40
- : [
41
- resolve(process.cwd(), '.stellavault.json'),
42
- join(homedir(), '.stellavault.json'),
43
- ];
44
- for (const p of paths) {
45
- if (existsSync(p)) {
46
- const raw = JSON.parse(readFileSync(p, 'utf-8'));
47
- return mergeConfig(DEFAULT_CONFIG, raw);
48
- }
49
- }
50
- return { ...DEFAULT_CONFIG };
51
- }
52
- function mergeConfig(defaults, overrides) {
53
- return {
54
- vaultPath: overrides.vaultPath ?? defaults.vaultPath,
55
- dbPath: overrides.dbPath ?? defaults.dbPath,
56
- folders: { ...defaults.folders, ...overrides.folders },
57
- embedding: { ...defaults.embedding, ...overrides.embedding },
58
- chunking: { ...defaults.chunking, ...overrides.chunking },
59
- search: { ...defaults.search, ...overrides.search },
60
- mcp: { ...defaults.mcp, ...overrides.mcp },
61
- };
62
- }
63
- //# sourceMappingURL=config.js.map
@@ -1,26 +0,0 @@
1
- export interface CreditAccount {
2
- balance: number;
3
- totalEarned: number;
4
- totalSpent: number;
5
- transactions: CreditTransaction[];
6
- }
7
- export interface CreditTransaction {
8
- type: 'earn' | 'spend';
9
- amount: number;
10
- reason: string;
11
- timestamp: string;
12
- }
13
- export declare function getBalance(): number;
14
- export declare function getAccount(): CreditAccount;
15
- export declare function earn(amount: number, reason: string): number;
16
- export declare function spend(amount: number, reason: string): {
17
- success: boolean;
18
- balance: number;
19
- };
20
- export declare function earnForSearchResponse(peerId: string): number;
21
- export declare function spendForSearch(peerCount: number): {
22
- success: boolean;
23
- balance: number;
24
- };
25
- export declare function getRecentTransactions(limit?: number): CreditTransaction[];
26
- //# sourceMappingURL=credits.d.ts.map
@@ -1,56 +0,0 @@
1
- // Federation Phase 2: Search Credits
2
- // 지식 공유 = 크레딧 획득, 연합 검색 = 크레딧 소모
3
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
4
- import { join } from 'node:path';
5
- import { homedir } from 'node:os';
6
- const CREDITS_FILE = join(homedir(), '.stellavault', 'federation', 'credits.json');
7
- const INITIAL_BALANCE = 100;
8
- const EARN_PER_SEARCH_RESPONSE = 10; // 검색 응답 시 획득
9
- const COST_PER_SEARCH = 1; // 검색 요청 시 소모
10
- function loadAccount() {
11
- if (existsSync(CREDITS_FILE)) {
12
- return JSON.parse(readFileSync(CREDITS_FILE, 'utf-8'));
13
- }
14
- return { balance: INITIAL_BALANCE, totalEarned: 0, totalSpent: 0, transactions: [] };
15
- }
16
- function saveAccount(account) {
17
- mkdirSync(join(homedir(), '.stellavault', 'federation'), { recursive: true });
18
- // 최근 100개 트랜잭션만 유지
19
- account.transactions = account.transactions.slice(-100);
20
- writeFileSync(CREDITS_FILE, JSON.stringify(account, null, 2), 'utf-8');
21
- }
22
- export function getBalance() {
23
- return loadAccount().balance;
24
- }
25
- export function getAccount() {
26
- return loadAccount();
27
- }
28
- export function earn(amount, reason) {
29
- const account = loadAccount();
30
- account.balance += amount;
31
- account.totalEarned += amount;
32
- account.transactions.push({ type: 'earn', amount, reason, timestamp: new Date().toISOString() });
33
- saveAccount(account);
34
- return account.balance;
35
- }
36
- export function spend(amount, reason) {
37
- const account = loadAccount();
38
- if (account.balance < amount) {
39
- return { success: false, balance: account.balance };
40
- }
41
- account.balance -= amount;
42
- account.totalSpent += amount;
43
- account.transactions.push({ type: 'spend', amount, reason, timestamp: new Date().toISOString() });
44
- saveAccount(account);
45
- return { success: true, balance: account.balance };
46
- }
47
- export function earnForSearchResponse(peerId) {
48
- return earn(EARN_PER_SEARCH_RESPONSE, `Search response to ${peerId}`);
49
- }
50
- export function spendForSearch(peerCount) {
51
- return spend(COST_PER_SEARCH * peerCount, `Search across ${peerCount} peers`);
52
- }
53
- export function getRecentTransactions(limit = 20) {
54
- return loadAccount().transactions.slice(-limit).reverse();
55
- }
56
- //# sourceMappingURL=credits.js.map
@@ -1,14 +0,0 @@
1
- export interface NodeIdentity {
2
- peerId: string;
3
- publicKey: Buffer;
4
- secretKey: Buffer;
5
- displayName: string;
6
- createdAt: string;
7
- }
8
- export declare function getOrCreateIdentity(displayName?: string): NodeIdentity;
9
- export declare function signMessage(secretKey: Buffer, message: Buffer): Buffer;
10
- export declare function verifySignature(publicKey: Buffer, secretKey: Buffer, message: Buffer, signature: Buffer): boolean;
11
- export declare function createChallenge(): Buffer;
12
- export declare function respondToChallenge(secretKey: Buffer, challenge: Buffer): Buffer;
13
- export declare function verifyChallenge(secretKey: Buffer, challenge: Buffer, response: Buffer): boolean;
14
- //# sourceMappingURL=identity.d.ts.map
@@ -1,74 +0,0 @@
1
- // Federation: Node Identity (HMAC-SHA256 signing)
2
- // CRIT-01 fix: 실제 서명 검증 구현 (placeholder 제거)
3
- // CRIT-04 fix: 키 파일 권한 0o600
4
- import { randomBytes, createHash, createHmac } from 'node:crypto';
5
- import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'node:fs';
6
- import { join } from 'node:path';
7
- import { homedir } from 'node:os';
8
- const IDENTITY_DIR = join(homedir(), '.stellavault', 'federation');
9
- const IDENTITY_FILE = join(IDENTITY_DIR, 'identity.json');
10
- export function getOrCreateIdentity(displayName) {
11
- if (existsSync(IDENTITY_FILE)) {
12
- const raw = JSON.parse(readFileSync(IDENTITY_FILE, 'utf-8'));
13
- return {
14
- peerId: raw.peerId,
15
- publicKey: Buffer.from(raw.publicKey, 'hex'),
16
- secretKey: Buffer.from(raw.secretKey, 'hex'),
17
- displayName: raw.displayName,
18
- createdAt: raw.createdAt,
19
- };
20
- }
21
- const secretKey = randomBytes(32);
22
- const publicKey = createHash('sha256').update(secretKey).digest();
23
- const peerId = createHash('sha256').update(publicKey).digest('hex').slice(0, 16);
24
- const identity = {
25
- peerId,
26
- publicKey,
27
- secretKey,
28
- displayName: displayName ?? `node-${peerId.slice(0, 6)}`,
29
- createdAt: new Date().toISOString(),
30
- };
31
- mkdirSync(IDENTITY_DIR, { recursive: true });
32
- const content = JSON.stringify({
33
- peerId: identity.peerId,
34
- publicKey: publicKey.toString('hex'),
35
- secretKey: secretKey.toString('hex'),
36
- displayName: identity.displayName,
37
- createdAt: identity.createdAt,
38
- }, null, 2);
39
- writeFileSync(IDENTITY_FILE, content, { encoding: 'utf-8', mode: 0o600 });
40
- try {
41
- chmodSync(IDENTITY_FILE, 0o600);
42
- }
43
- catch { /* Windows may not support */ }
44
- return identity;
45
- }
46
- // CRIT-01 fix: 실제 HMAC-SHA256 서명
47
- export function signMessage(secretKey, message) {
48
- return createHmac('sha256', secretKey).update(message).digest();
49
- }
50
- // CRIT-01 fix: 실제 HMAC-SHA256 검증
51
- export function verifySignature(publicKey, secretKey, message, signature) {
52
- const expected = createHmac('sha256', secretKey).update(message).digest();
53
- if (expected.length !== signature.length)
54
- return false;
55
- // Timing-safe comparison
56
- let diff = 0;
57
- for (let i = 0; i < expected.length; i++) {
58
- diff |= expected[i] ^ signature[i];
59
- }
60
- return diff === 0;
61
- }
62
- // Challenge-response 인증용 nonce 생성
63
- export function createChallenge() {
64
- return randomBytes(32);
65
- }
66
- // Challenge에 대한 응답 생성
67
- export function respondToChallenge(secretKey, challenge) {
68
- return signMessage(secretKey, challenge);
69
- }
70
- // Challenge 응답 검증
71
- export function verifyChallenge(secretKey, challenge, response) {
72
- return verifySignature(Buffer.alloc(0), secretKey, challenge, response);
73
- }
74
- //# sourceMappingURL=identity.js.map
@@ -1,7 +0,0 @@
1
- export { FederationNode } from './node.js';
2
- export { FederatedSearch } from './search.js';
3
- export type { FederatedSearchOptions } from './search.js';
4
- export { getOrCreateIdentity } from './identity.js';
5
- export type { NodeIdentity } from './identity.js';
6
- export type { PeerInfo, FederatedSearchResult, FederationMessage } from './types.js';
7
- //# sourceMappingURL=index.d.ts.map
@@ -1,5 +0,0 @@
1
- // Design Ref: §2.3 — Federation Public API
2
- export { FederationNode } from './node.js';
3
- export { FederatedSearch } from './search.js';
4
- export { getOrCreateIdentity } from './identity.js';
5
- //# sourceMappingURL=index.js.map
@@ -1,31 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import type { PeerInfo } from './types.js';
3
- export declare class FederationNode extends EventEmitter {
4
- private swarm;
5
- private identity;
6
- private peers;
7
- private running;
8
- private documentCount;
9
- private topTopics;
10
- constructor(displayName?: string);
11
- get peerId(): string;
12
- get displayName(): string;
13
- get peerCount(): number;
14
- get isRunning(): boolean;
15
- setLocalStats(documentCount: number, topTopics: string[]): void;
16
- join(): Promise<void>;
17
- joinDirect(host: string, port: number): Promise<void>;
18
- leave(): Promise<void>;
19
- getPeers(): PeerInfo[];
20
- sendSearchQuery(peerId: string, queryId: string, embedding: number[], limit: number): void;
21
- sendSearchResult(peerId: string, queryId: string, results: Array<{
22
- title: string;
23
- similarity: number;
24
- snippet: string;
25
- }>): void;
26
- private handleConnection;
27
- private validateMessage;
28
- private handleMessage;
29
- private sendMessage;
30
- }
31
- //# sourceMappingURL=node.d.ts.map