stellavault 0.1.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.
- package/.env.example +12 -0
- package/CLAUDE.md +39 -0
- package/CONTRIBUTING.md +65 -0
- package/LICENSE +21 -0
- package/README.md +182 -0
- package/memory/MEMORY.md +25 -0
- package/package.json +33 -0
- package/packages/cli/bin/ekh.js +2 -0
- package/packages/cli/bin/stellavault.js +2 -0
- package/packages/cli/dist/commands/brief-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/brief-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/brief-cmd.js +82 -0
- package/packages/cli/dist/commands/brief-cmd.js.map +1 -0
- package/packages/cli/dist/commands/capture-cmd.d.ts +7 -0
- package/packages/cli/dist/commands/capture-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/capture-cmd.js +31 -0
- package/packages/cli/dist/commands/capture-cmd.js.map +1 -0
- package/packages/cli/dist/commands/card-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/card-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/card-cmd.js +26 -0
- package/packages/cli/dist/commands/card-cmd.js.map +1 -0
- package/packages/cli/dist/commands/clip-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/clip-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/clip-cmd.js +151 -0
- package/packages/cli/dist/commands/clip-cmd.js.map +1 -0
- package/packages/cli/dist/commands/cloud-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/cloud-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/cloud-cmd.js +64 -0
- package/packages/cli/dist/commands/cloud-cmd.js.map +1 -0
- package/packages/cli/dist/commands/contradictions-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/contradictions-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/contradictions-cmd.js +34 -0
- package/packages/cli/dist/commands/contradictions-cmd.js.map +1 -0
- package/packages/cli/dist/commands/decay-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/decay-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/decay-cmd.js +48 -0
- package/packages/cli/dist/commands/decay-cmd.js.map +1 -0
- package/packages/cli/dist/commands/digest-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/digest-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/digest-cmd.js +79 -0
- package/packages/cli/dist/commands/digest-cmd.js.map +1 -0
- package/packages/cli/dist/commands/duplicates-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/duplicates-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/duplicates-cmd.js +30 -0
- package/packages/cli/dist/commands/duplicates-cmd.js.map +1 -0
- package/packages/cli/dist/commands/federate-cmd.d.ts +5 -0
- package/packages/cli/dist/commands/federate-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/federate-cmd.js +217 -0
- package/packages/cli/dist/commands/federate-cmd.js.map +1 -0
- package/packages/cli/dist/commands/gaps-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/gaps-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/gaps-cmd.js +33 -0
- package/packages/cli/dist/commands/gaps-cmd.js.map +1 -0
- package/packages/cli/dist/commands/graph-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/graph-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/graph-cmd.js +77 -0
- package/packages/cli/dist/commands/graph-cmd.js.map +1 -0
- package/packages/cli/dist/commands/index-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/index-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/index-cmd.js +57 -0
- package/packages/cli/dist/commands/index-cmd.js.map +1 -0
- package/packages/cli/dist/commands/init-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/init-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/init-cmd.js +123 -0
- package/packages/cli/dist/commands/init-cmd.js.map +1 -0
- package/packages/cli/dist/commands/learn-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/learn-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/learn-cmd.js +48 -0
- package/packages/cli/dist/commands/learn-cmd.js.map +1 -0
- package/packages/cli/dist/commands/pack-cmd.d.ts +15 -0
- package/packages/cli/dist/commands/pack-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/pack-cmd.js +93 -0
- package/packages/cli/dist/commands/pack-cmd.js.map +1 -0
- package/packages/cli/dist/commands/review-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/review-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/review-cmd.js +107 -0
- package/packages/cli/dist/commands/review-cmd.js.map +1 -0
- package/packages/cli/dist/commands/search-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/search-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/search-cmd.js +38 -0
- package/packages/cli/dist/commands/search-cmd.js.map +1 -0
- package/packages/cli/dist/commands/serve-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/serve-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/serve-cmd.js +14 -0
- package/packages/cli/dist/commands/serve-cmd.js.map +1 -0
- package/packages/cli/dist/commands/status-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/status-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/status-cmd.js +33 -0
- package/packages/cli/dist/commands/status-cmd.js.map +1 -0
- package/packages/cli/dist/commands/sync-cmd.d.ts +5 -0
- package/packages/cli/dist/commands/sync-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/sync-cmd.js +62 -0
- package/packages/cli/dist/commands/sync-cmd.js.map +1 -0
- package/packages/cli/dist/commands/vault-cmd.d.ts +10 -0
- package/packages/cli/dist/commands/vault-cmd.d.ts.map +1 -0
- package/packages/cli/dist/commands/vault-cmd.js +54 -0
- package/packages/cli/dist/commands/vault-cmd.js.map +1 -0
- package/packages/cli/dist/index.d.ts +2 -0
- package/packages/cli/dist/index.d.ts.map +1 -0
- package/packages/cli/dist/index.js +156 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/cli/package.json +24 -0
- package/packages/cli/src/commands/brief-cmd.ts +87 -0
- package/packages/cli/src/commands/capture-cmd.ts +34 -0
- package/packages/cli/src/commands/card-cmd.ts +29 -0
- package/packages/cli/src/commands/clip-cmd.ts +172 -0
- package/packages/cli/src/commands/cloud-cmd.ts +75 -0
- package/packages/cli/src/commands/contradictions-cmd.ts +41 -0
- package/packages/cli/src/commands/decay-cmd.ts +57 -0
- package/packages/cli/src/commands/digest-cmd.ts +89 -0
- package/packages/cli/src/commands/duplicates-cmd.ts +38 -0
- package/packages/cli/src/commands/federate-cmd.ts +236 -0
- package/packages/cli/src/commands/gaps-cmd.ts +40 -0
- package/packages/cli/src/commands/graph-cmd.ts +88 -0
- package/packages/cli/src/commands/index-cmd.ts +65 -0
- package/packages/cli/src/commands/init-cmd.ts +145 -0
- package/packages/cli/src/commands/learn-cmd.ts +56 -0
- package/packages/cli/src/commands/pack-cmd.ts +121 -0
- package/packages/cli/src/commands/review-cmd.ts +125 -0
- package/packages/cli/src/commands/search-cmd.ts +45 -0
- package/packages/cli/src/commands/serve-cmd.ts +17 -0
- package/packages/cli/src/commands/status-cmd.ts +37 -0
- package/packages/cli/src/commands/sync-cmd.ts +68 -0
- package/packages/cli/src/commands/vault-cmd.ts +64 -0
- package/packages/cli/src/index.ts +187 -0
- package/packages/core/package.json +40 -0
- package/packages/core/src/api/dashboard.ts +138 -0
- package/packages/core/src/api/graph-data.ts +286 -0
- package/packages/core/src/api/pwa.ts +82 -0
- package/packages/core/src/api/server.ts +660 -0
- package/packages/core/src/capture/voice.ts +168 -0
- package/packages/core/src/cloud/index.ts +2 -0
- package/packages/core/src/cloud/sync.ts +167 -0
- package/packages/core/src/config.ts +82 -0
- package/packages/core/src/federation/credits.ts +80 -0
- package/packages/core/src/federation/hyperswarm.d.ts +19 -0
- package/packages/core/src/federation/identity.ts +90 -0
- package/packages/core/src/federation/index.ts +8 -0
- package/packages/core/src/federation/node.ts +235 -0
- package/packages/core/src/federation/privacy.ts +52 -0
- package/packages/core/src/federation/reputation.ts +202 -0
- package/packages/core/src/federation/search.ts +129 -0
- package/packages/core/src/federation/sharing.ts +165 -0
- package/packages/core/src/federation/trust.ts +76 -0
- package/packages/core/src/federation/types.ts +25 -0
- package/packages/core/src/i18n/index.ts +85 -0
- package/packages/core/src/index.ts +133 -0
- package/packages/core/src/indexer/chunker.ts +180 -0
- package/packages/core/src/indexer/embedder.ts +9 -0
- package/packages/core/src/indexer/index.ts +113 -0
- package/packages/core/src/indexer/local-embedder.ts +35 -0
- package/packages/core/src/indexer/scanner.ts +142 -0
- package/packages/core/src/indexer/watcher.ts +62 -0
- package/packages/core/src/intelligence/contradiction-detector.ts +134 -0
- package/packages/core/src/intelligence/decay-engine.ts +229 -0
- package/packages/core/src/intelligence/duplicate-detector.ts +71 -0
- package/packages/core/src/intelligence/fsrs.ts +79 -0
- package/packages/core/src/intelligence/gap-detector.ts +109 -0
- package/packages/core/src/intelligence/learning-path.ts +86 -0
- package/packages/core/src/intelligence/notifications.ts +106 -0
- package/packages/core/src/intelligence/predictive-gaps.ts +94 -0
- package/packages/core/src/intelligence/semantic-versioning.ts +97 -0
- package/packages/core/src/intelligence/types.ts +28 -0
- package/packages/core/src/mcp/custom-tools.ts +97 -0
- package/packages/core/src/mcp/index.ts +1 -0
- package/packages/core/src/mcp/server.ts +142 -0
- package/packages/core/src/mcp/tools/agentic-graph.ts +96 -0
- package/packages/core/src/mcp/tools/brief.ts +49 -0
- package/packages/core/src/mcp/tools/decay.ts +40 -0
- package/packages/core/src/mcp/tools/decision-journal.ts +95 -0
- package/packages/core/src/mcp/tools/export.ts +72 -0
- package/packages/core/src/mcp/tools/federated-search.ts +43 -0
- package/packages/core/src/mcp/tools/generate-claude-md.ts +130 -0
- package/packages/core/src/mcp/tools/get-document.ts +26 -0
- package/packages/core/src/mcp/tools/get-related.ts +41 -0
- package/packages/core/src/mcp/tools/learning-path.ts +52 -0
- package/packages/core/src/mcp/tools/list-topics.ts +20 -0
- package/packages/core/src/mcp/tools/search.ts +35 -0
- package/packages/core/src/mcp/tools/snapshot.ts +98 -0
- package/packages/core/src/multi-vault/index.ts +118 -0
- package/packages/core/src/pack/creator.ts +127 -0
- package/packages/core/src/pack/exporter.ts +21 -0
- package/packages/core/src/pack/importer.ts +82 -0
- package/packages/core/src/pack/index.ts +5 -0
- package/packages/core/src/pack/marketplace.ts +103 -0
- package/packages/core/src/pack/pii-masker.ts +38 -0
- package/packages/core/src/pack/types.ts +39 -0
- package/packages/core/src/plugins/index.ts +100 -0
- package/packages/core/src/plugins/webhooks.ts +110 -0
- package/packages/core/src/search/bm25.ts +16 -0
- package/packages/core/src/search/index.ts +83 -0
- package/packages/core/src/search/rrf.ts +31 -0
- package/packages/core/src/search/semantic.ts +15 -0
- package/packages/core/src/store/index.ts +2 -0
- package/packages/core/src/store/sqlite-vec.ts +290 -0
- package/packages/core/src/store/types.ts +22 -0
- package/packages/core/src/team/index.ts +126 -0
- package/packages/core/src/types/chunk.ts +25 -0
- package/packages/core/src/types/document.ts +24 -0
- package/packages/core/src/types/graph.ts +44 -0
- package/packages/core/src/types/index.ts +15 -0
- package/packages/core/src/types/search.ts +38 -0
- package/packages/core/src/utils/retry.ts +85 -0
- package/packages/core/tests/api-card.test.ts +60 -0
- package/packages/core/tests/api-routes.test.ts +98 -0
- package/packages/core/tests/bm25.test.ts +87 -0
- package/packages/core/tests/chunker.test.ts +48 -0
- package/packages/core/tests/cluster.test.ts +75 -0
- package/packages/core/tests/constellation.test.ts +77 -0
- package/packages/core/tests/export-utils.test.ts +97 -0
- package/packages/core/tests/fsrs.test.ts +96 -0
- package/packages/core/tests/gesture-detector.test.ts +45 -0
- package/packages/core/tests/graph-data.test.ts +87 -0
- package/packages/core/tests/layout.test.ts +83 -0
- package/packages/core/tests/mcp.test.ts +148 -0
- package/packages/core/tests/pack.test.ts +127 -0
- package/packages/core/tests/pii-masker.test.ts +42 -0
- package/packages/core/tests/profile-card.test.ts +62 -0
- package/packages/core/tests/rrf.test.ts +29 -0
- package/packages/core/tests/search-integration.test.ts +139 -0
- package/packages/core/tests/store.test.ts +80 -0
- package/packages/graph/click-result.png +0 -0
- package/packages/graph/index.html +17 -0
- package/packages/graph/package.json +32 -0
- package/packages/graph/src/App.tsx +7 -0
- package/packages/graph/src/api/client.ts +39 -0
- package/packages/graph/src/components/ClusterFilter.tsx +73 -0
- package/packages/graph/src/components/ConstellationView.tsx +232 -0
- package/packages/graph/src/components/ExportPanel.tsx +177 -0
- package/packages/graph/src/components/Graph3D.tsx +230 -0
- package/packages/graph/src/components/GraphEdges.tsx +100 -0
- package/packages/graph/src/components/GraphNodes.tsx +386 -0
- package/packages/graph/src/components/HealthDashboard.tsx +173 -0
- package/packages/graph/src/components/Layout.tsx +214 -0
- package/packages/graph/src/components/MotionOverlay.tsx +81 -0
- package/packages/graph/src/components/MotionToggle.tsx +33 -0
- package/packages/graph/src/components/MultiverseView.tsx +286 -0
- package/packages/graph/src/components/NodeDetail.tsx +232 -0
- package/packages/graph/src/components/PulseParticle.tsx +232 -0
- package/packages/graph/src/components/SearchBar.tsx +107 -0
- package/packages/graph/src/components/StarField.tsx +197 -0
- package/packages/graph/src/components/StatusBar.tsx +53 -0
- package/packages/graph/src/components/Timeline.tsx +148 -0
- package/packages/graph/src/components/ToolsPanel.tsx +512 -0
- package/packages/graph/src/components/Tooltip.tsx +100 -0
- package/packages/graph/src/components/TypeFilter.tsx +131 -0
- package/packages/graph/src/embed/EmbedGraph.tsx +144 -0
- package/packages/graph/src/hooks/useConstellationLOD.ts +76 -0
- package/packages/graph/src/hooks/useDecay.ts +37 -0
- package/packages/graph/src/hooks/useExport.ts +165 -0
- package/packages/graph/src/hooks/useGraph.ts +69 -0
- package/packages/graph/src/hooks/useKeyboardNav.ts +122 -0
- package/packages/graph/src/hooks/useLayout.ts +45 -0
- package/packages/graph/src/hooks/useMotion.ts +120 -0
- package/packages/graph/src/hooks/usePulse.ts +58 -0
- package/packages/graph/src/hooks/useSearch.ts +71 -0
- package/packages/graph/src/lib/constellation.ts +107 -0
- package/packages/graph/src/lib/export-utils.ts +48 -0
- package/packages/graph/src/lib/gesture-detector.ts +123 -0
- package/packages/graph/src/lib/layout.worker.ts +153 -0
- package/packages/graph/src/lib/motion-controller.ts +83 -0
- package/packages/graph/src/lib/profile-card.ts +122 -0
- package/packages/graph/src/main.tsx +4 -0
- package/packages/graph/src/stores/graph-store.ts +155 -0
- package/packages/graph/success.png +0 -0
- package/packages/graph/test-click.mjs +49 -0
- package/packages/graph/test-explore.mjs +102 -0
- package/packages/graph/test-final.mjs +61 -0
- package/packages/graph/test-graph.mjs +139 -0
- package/packages/graph/test-hover.mjs +48 -0
- package/packages/graph/test-pulse.mjs +68 -0
- package/packages/graph/test-screenshot.mjs +56 -0
- package/packages/graph/test-v2.mjs +97 -0
- package/packages/graph/vite.config.ts +15 -0
- package/packages/sync/.env.example +11 -0
- package/packages/sync/.sync-state.json +317 -0
- package/packages/sync/.upload-state.json +1009 -0
- package/packages/sync/create-stella-network-notion.mjs +151 -0
- package/packages/sync/create-stellavault-project-notion.mjs +322 -0
- package/packages/sync/logs/sync-2026-03-28.log +6 -0
- package/packages/sync/logs/sync-2026-03-29.log +12 -0
- package/packages/sync/logs/sync-2026-03-30.log +6 -0
- package/packages/sync/logs/sync-2026-03-31.log +6 -0
- package/packages/sync/logs/sync-2026-04-01.log +6 -0
- package/packages/sync/logs/sync-2026-04-02.log +6 -0
- package/packages/sync/package-lock.json +373 -0
- package/packages/sync/package.json +16 -0
- package/packages/sync/run-sync.bat +18 -0
- package/packages/sync/run-sync.mjs +46 -0
- package/packages/sync/setup-scheduler.mjs +119 -0
- package/packages/sync/structured-sync.mjs +187 -0
- package/packages/sync/sync-to-obsidian.mjs +264 -0
- package/packages/sync/upload-pdca-to-notion.mjs +495 -0
- package/tsconfig.base.json +18 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// stellavault init β μΈν°λν°λΈ μ¨λ³΄λ© μμ λ (F-A01)
|
|
2
|
+
|
|
3
|
+
import { createInterface } from 'node:readline';
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { loadConfig, createSqliteVecStore, createLocalEmbedder, indexVault, createSearchEngine } from '@stellavault/core';
|
|
10
|
+
|
|
11
|
+
function ask(rl: ReturnType<typeof createInterface>, question: string, defaultVal?: string): Promise<string> {
|
|
12
|
+
const suffix = defaultVal ? ` ${chalk.dim(`(${defaultVal})`)}` : '';
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
15
|
+
resolve(answer.trim() || defaultVal || '');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function initCommand() {
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log(chalk.bold(' β¦ Stellavault Setup Wizard'));
|
|
23
|
+
console.log(chalk.dim(' Notes die in folders. Let\'s bring yours to life.\n'));
|
|
24
|
+
|
|
25
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Step 1: Vault Path
|
|
29
|
+
console.log(chalk.cyan(' Step 1/3') + ' β Where is your Obsidian vault?');
|
|
30
|
+
console.log(chalk.dim(' This is the folder containing your .md files.\n'));
|
|
31
|
+
|
|
32
|
+
let vaultPath = '';
|
|
33
|
+
while (!vaultPath) {
|
|
34
|
+
const input = await ask(rl, ' Vault path');
|
|
35
|
+
if (!input) {
|
|
36
|
+
console.log(chalk.yellow(' Please enter your vault path.'));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const resolved = input.replace(/^~/, homedir());
|
|
40
|
+
if (!existsSync(resolved)) {
|
|
41
|
+
console.log(chalk.yellow(` Path not found: ${resolved}`));
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
vaultPath = resolved;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(chalk.green(` β Vault: ${vaultPath}\n`));
|
|
48
|
+
|
|
49
|
+
// Save config
|
|
50
|
+
const configDir = join(homedir(), '.stellavault');
|
|
51
|
+
mkdirSync(configDir, { recursive: true });
|
|
52
|
+
const dbPath = join(configDir, 'index.db');
|
|
53
|
+
|
|
54
|
+
const configData = {
|
|
55
|
+
vaultPath,
|
|
56
|
+
dbPath,
|
|
57
|
+
embedding: { model: 'local', localModel: 'all-MiniLM-L6-v2' },
|
|
58
|
+
chunking: { maxTokens: 300, overlap: 50, minTokens: 50 },
|
|
59
|
+
search: { defaultLimit: 10, rrfK: 60 },
|
|
60
|
+
mcp: { mode: 'stdio', port: 3333 },
|
|
61
|
+
};
|
|
62
|
+
writeFileSync(join(homedir(), '.stellavault.json'), JSON.stringify(configData, null, 2), 'utf-8');
|
|
63
|
+
console.log(chalk.dim(` Config saved: ~/.stellavault.json`));
|
|
64
|
+
|
|
65
|
+
// Step 2: Indexing
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(chalk.cyan(' Step 2/3') + ' β Indexing your vault');
|
|
68
|
+
console.log(chalk.dim(' Vectorizing notes with local AI (no data leaves your machine).\n'));
|
|
69
|
+
|
|
70
|
+
const spinner = ora({ text: ' Loading embedding model...', indent: 2 }).start();
|
|
71
|
+
|
|
72
|
+
const store = createSqliteVecStore(dbPath);
|
|
73
|
+
await store.initialize();
|
|
74
|
+
|
|
75
|
+
const embedder = createLocalEmbedder('all-MiniLM-L6-v2');
|
|
76
|
+
await embedder.initialize();
|
|
77
|
+
spinner.text = ' Scanning vault...';
|
|
78
|
+
|
|
79
|
+
const result = await indexVault(vaultPath, {
|
|
80
|
+
store,
|
|
81
|
+
embedder,
|
|
82
|
+
chunkOptions: { maxTokens: 300, overlap: 50, minTokens: 50 },
|
|
83
|
+
onProgress(current, total, doc) {
|
|
84
|
+
const pct = Math.round((current / total) * 100);
|
|
85
|
+
const bar = 'β'.repeat(Math.floor(pct / 4)) + 'β'.repeat(25 - Math.floor(pct / 4));
|
|
86
|
+
spinner.text = ` [${bar}] ${pct}% (${current}/${total}) ${doc.title.slice(0, 30)}`;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
spinner.succeed(chalk.green(` Indexed ${result.indexed} docs, ${result.totalChunks} chunks (${(result.elapsedMs / 1000).toFixed(1)}s)`));
|
|
91
|
+
|
|
92
|
+
// Step 3: First Search
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(chalk.cyan(' Step 3/3') + ' β Try your first search');
|
|
95
|
+
console.log(chalk.dim(' Type a topic you know about. Stellavault finds connections.\n'));
|
|
96
|
+
|
|
97
|
+
const searchEngine = createSearchEngine({ store, embedder, rrfK: 60 });
|
|
98
|
+
|
|
99
|
+
let searchDone = false;
|
|
100
|
+
while (!searchDone) {
|
|
101
|
+
const query = await ask(rl, ' Search');
|
|
102
|
+
if (!query) {
|
|
103
|
+
console.log(chalk.dim(' Type something, or press Ctrl+C to skip.'));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const searchSpinner = ora({ text: ' Searching...', indent: 2 }).start();
|
|
108
|
+
const results = await searchEngine.search({ query, limit: 5 });
|
|
109
|
+
searchSpinner.stop();
|
|
110
|
+
|
|
111
|
+
if (results.length === 0) {
|
|
112
|
+
console.log(chalk.yellow(' No results. Try a different topic.'));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('');
|
|
117
|
+
for (const r of results) {
|
|
118
|
+
const score = Math.round(r.score * 100);
|
|
119
|
+
const bar = score >= 70 ? chalk.green('β') : score >= 40 ? chalk.yellow('β') : chalk.dim('β');
|
|
120
|
+
console.log(` ${bar} ${chalk.bold(r.document.title)} ${chalk.dim(`(${score}%)`)}`);
|
|
121
|
+
if (r.highlights[0]) {
|
|
122
|
+
console.log(` ${chalk.dim(r.highlights[0].slice(0, 80))}...`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log('');
|
|
126
|
+
searchDone = true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await store.close();
|
|
130
|
+
|
|
131
|
+
// Done!
|
|
132
|
+
console.log(chalk.bold.green(' β¦ Setup complete!\n'));
|
|
133
|
+
console.log(' What\'s next:');
|
|
134
|
+
console.log(` ${chalk.cyan('stellavault graph')} Launch 3D knowledge graph`);
|
|
135
|
+
console.log(` ${chalk.cyan('stellavault decay')} See what knowledge is fading`);
|
|
136
|
+
console.log(` ${chalk.cyan('stellavault brief')} Get your daily knowledge briefing`);
|
|
137
|
+
console.log(` ${chalk.cyan('stellavault serve')} Connect AI agents via MCP`);
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(chalk.dim(' Your knowledge is now alive. β¦'));
|
|
140
|
+
console.log('');
|
|
141
|
+
|
|
142
|
+
} finally {
|
|
143
|
+
rl.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// stellavault learn β AI learning path recommendations (F-A11)
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { loadConfig, createKnowledgeHub, DecayEngine, detectKnowledgeGaps, generateLearningPath } from '@stellavault/core';
|
|
5
|
+
|
|
6
|
+
export async function learnCommand(_opts: any, cmd: any) {
|
|
7
|
+
const globalOpts = cmd?.parent?.opts?.() ?? {};
|
|
8
|
+
const jsonMode = globalOpts.json;
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const hub = createKnowledgeHub(config);
|
|
11
|
+
|
|
12
|
+
await hub.store.initialize();
|
|
13
|
+
await hub.embedder.initialize();
|
|
14
|
+
|
|
15
|
+
const db = hub.store.getDb() as any;
|
|
16
|
+
if (!db) { console.error(chalk.red('Cannot access database')); process.exit(1); }
|
|
17
|
+
|
|
18
|
+
const decayEngine = new DecayEngine(db);
|
|
19
|
+
const decayReport = await decayEngine.computeAll();
|
|
20
|
+
|
|
21
|
+
let gaps: any[] = [];
|
|
22
|
+
try {
|
|
23
|
+
const gapReport = await detectKnowledgeGaps(hub.store);
|
|
24
|
+
gaps = gapReport.gaps ?? [];
|
|
25
|
+
} catch { /* gaps may fail without enough data */ }
|
|
26
|
+
|
|
27
|
+
const path = generateLearningPath({ decayReport, gaps }, 15);
|
|
28
|
+
await hub.store.close();
|
|
29
|
+
|
|
30
|
+
if (jsonMode) {
|
|
31
|
+
console.log(JSON.stringify(path, null, 2));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(chalk.bold(' π― Your Learning Path'));
|
|
37
|
+
console.log(chalk.dim(` ${path.summary.reviewCount} to review Β· ${path.summary.bridgeCount} gaps to bridge Β· ~${path.summary.estimatedMinutes}min`));
|
|
38
|
+
console.log('');
|
|
39
|
+
|
|
40
|
+
for (const item of path.items) {
|
|
41
|
+
const icon = item.category === 'review' ? 'π' : item.category === 'bridge' ? 'π' : 'π';
|
|
42
|
+
const prioColor = item.priority === 'critical' ? chalk.red : item.priority === 'important' ? chalk.yellow : chalk.dim;
|
|
43
|
+
const prioLabel = prioColor(item.priority.toUpperCase());
|
|
44
|
+
|
|
45
|
+
console.log(` ${icon} ${prioLabel} ${chalk.bold(item.title)} ${chalk.dim(`(${item.score}pt)`)}`);
|
|
46
|
+
console.log(` ${chalk.dim(item.reason)}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (path.items.length === 0) {
|
|
50
|
+
console.log(chalk.green(' All clear! Your knowledge is in great shape.'));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log(chalk.dim(' π‘ stellavault review β start reviewing decaying notes'));
|
|
55
|
+
console.log('');
|
|
56
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// stellavault pack β Knowledge Pack κ΄λ¦¬
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { resolve, join } from 'node:path';
|
|
5
|
+
import { readdirSync, existsSync, readFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import {
|
|
8
|
+
loadConfig, createKnowledgeHub,
|
|
9
|
+
createPack, exportPack, importPack, packToSummary,
|
|
10
|
+
} from '@stellavault/core';
|
|
11
|
+
|
|
12
|
+
const PACKS_DIR = join(homedir(), '.stellavault', 'packs');
|
|
13
|
+
|
|
14
|
+
export async function packCreateCommand(name: string, options: {
|
|
15
|
+
fromSearch?: string;
|
|
16
|
+
fromCluster?: string;
|
|
17
|
+
author?: string;
|
|
18
|
+
license?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
limit?: string;
|
|
21
|
+
}) {
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
const hub = createKnowledgeHub(config);
|
|
24
|
+
await hub.store.initialize();
|
|
25
|
+
await hub.embedder.initialize();
|
|
26
|
+
|
|
27
|
+
console.error(chalk.dim('β³ Creating pack...'));
|
|
28
|
+
|
|
29
|
+
const { pack, piiReport } = await createPack(hub.store, hub.searchEngine, hub.embedder, {
|
|
30
|
+
name,
|
|
31
|
+
fromSearch: options.fromSearch,
|
|
32
|
+
fromCluster: options.fromCluster ? parseInt(options.fromCluster) : undefined,
|
|
33
|
+
author: options.author ?? 'anonymous',
|
|
34
|
+
license: options.license ?? 'CC-BY-4.0',
|
|
35
|
+
description: options.description,
|
|
36
|
+
limit: options.limit ? parseInt(options.limit) : 100,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
mkdirSync(PACKS_DIR, { recursive: true });
|
|
40
|
+
const outPath = join(PACKS_DIR, `${name}.sv-pack`);
|
|
41
|
+
exportPack(pack, outPath);
|
|
42
|
+
|
|
43
|
+
console.error(chalk.green(`β
Pack created: ${name}`));
|
|
44
|
+
console.error(` π¦ ${pack.chunks.length} chunks`);
|
|
45
|
+
console.error(` πΎ ${outPath}`);
|
|
46
|
+
if (piiReport.redactedCount > 0) {
|
|
47
|
+
console.error(chalk.yellow(` π PII masked: ${piiReport.redactedCount} items (${piiReport.types.join(', ')})`));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await hub.store.close();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function packExportCommand(name: string, options: { output?: string }) {
|
|
54
|
+
const srcPath = join(PACKS_DIR, `${name}.sv-pack`);
|
|
55
|
+
if (!existsSync(srcPath)) {
|
|
56
|
+
console.error(chalk.red(`β Pack not found: ${name}`));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const outPath = resolve(process.cwd(), options.output ?? `${name}.sv-pack`);
|
|
61
|
+
const content = readFileSync(srcPath, 'utf-8');
|
|
62
|
+
const { writeFileSync } = await import('node:fs');
|
|
63
|
+
writeFileSync(outPath, content);
|
|
64
|
+
|
|
65
|
+
console.error(chalk.green(`β
Exported: ${outPath}`));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function packImportCommand(filePath: string) {
|
|
69
|
+
const absPath = resolve(process.cwd(), filePath);
|
|
70
|
+
if (!existsSync(absPath)) {
|
|
71
|
+
console.error(chalk.red(`β File not found: ${absPath}`));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const config = loadConfig();
|
|
76
|
+
const hub = createKnowledgeHub(config);
|
|
77
|
+
await hub.store.initialize();
|
|
78
|
+
await hub.embedder.initialize();
|
|
79
|
+
|
|
80
|
+
console.error(chalk.dim('β³ Importing pack...'));
|
|
81
|
+
const result = await importPack(hub.store, hub.embedder, absPath);
|
|
82
|
+
|
|
83
|
+
console.error(chalk.green(`β
Imported: ${result.imported} chunks`));
|
|
84
|
+
if (result.skipped > 0) console.error(chalk.yellow(` βοΈ Skipped: ${result.skipped}`));
|
|
85
|
+
if (result.modelMismatch) {
|
|
86
|
+
console.error(chalk.yellow(` β οΈ Model mismatch β ${result.reEmbedded} chunks re-embedded`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
await hub.store.close();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function packListCommand() {
|
|
93
|
+
mkdirSync(PACKS_DIR, { recursive: true });
|
|
94
|
+
const files = readdirSync(PACKS_DIR).filter(f => f.endsWith('.sv-pack'));
|
|
95
|
+
|
|
96
|
+
if (files.length === 0) {
|
|
97
|
+
console.error(chalk.dim('No packs found. Create one: stellavault pack create <name> --from-search <query>'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.error(chalk.green(`π¦ ${files.length} packs in ${PACKS_DIR}\n`));
|
|
102
|
+
for (const file of files) {
|
|
103
|
+
try {
|
|
104
|
+
const pack = JSON.parse(readFileSync(join(PACKS_DIR, file), 'utf-8'));
|
|
105
|
+
console.error(` ${chalk.bold(pack.name)} v${pack.version} β ${pack.chunks.length} chunks (${pack.license})`);
|
|
106
|
+
} catch {
|
|
107
|
+
console.error(` ${file} (invalid)`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function packInfoCommand(name: string) {
|
|
113
|
+
const filePath = join(PACKS_DIR, `${name}.sv-pack`);
|
|
114
|
+
if (!existsSync(filePath)) {
|
|
115
|
+
console.error(chalk.red(`β Pack not found: ${name}`));
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const pack = JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
120
|
+
console.error(packToSummary(pack));
|
|
121
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Design Ref: stellavault review β μΌμΌ μ§μ 리뷰 (FSRS κΈ°λ°)
|
|
2
|
+
// Plan SC: "μμ΄κ°λ μ§μ 리λ§μΈλ β μ€μ μ‘μ
"
|
|
3
|
+
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
import { loadConfig, createKnowledgeHub, DecayEngine } from '@stellavault/core';
|
|
7
|
+
|
|
8
|
+
export async function reviewCommand(options: { count?: string }) {
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const hub = createKnowledgeHub(config);
|
|
11
|
+
const count = parseInt(options.count ?? '5', 10);
|
|
12
|
+
|
|
13
|
+
console.error(chalk.dim('β³ Initializing...'));
|
|
14
|
+
await hub.store.initialize();
|
|
15
|
+
|
|
16
|
+
const db = hub.store.getDb() as any;
|
|
17
|
+
if (!db) {
|
|
18
|
+
console.error(chalk.red('β Cannot access database'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const decayEngine = new DecayEngine(db);
|
|
23
|
+
const decaying = await decayEngine.getDecaying(0.6, count);
|
|
24
|
+
|
|
25
|
+
if (decaying.length === 0) {
|
|
26
|
+
console.log(chalk.green('\nβ¨ λͺ¨λ μ§μμ΄ κ±΄κ°ν©λλ€! 리뷰ν λ
ΈνΈκ° μμ΅λλ€.'));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(chalk.green(`\nπ§ μ€λμ 리뷰 (${decaying.length}κ°)`));
|
|
31
|
+
console.log(chalk.dim('β'.repeat(50)));
|
|
32
|
+
|
|
33
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
34
|
+
const ask = (q: string): Promise<string> => new Promise(r => rl.question(q, r));
|
|
35
|
+
|
|
36
|
+
let reviewed = 0;
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < decaying.length; i++) {
|
|
39
|
+
const d = decaying[i];
|
|
40
|
+
const elapsed = Math.round(
|
|
41
|
+
(Date.now() - new Date(d.lastAccess).getTime()) / 86400000
|
|
42
|
+
);
|
|
43
|
+
const rBar = 'β'.repeat(Math.round(d.retrievability * 10))
|
|
44
|
+
+ 'β'.repeat(10 - Math.round(d.retrievability * 10));
|
|
45
|
+
const color = d.retrievability < 0.3 ? chalk.red : chalk.yellow;
|
|
46
|
+
|
|
47
|
+
console.log(`\n${chalk.bold(`[${i + 1}/${decaying.length}]`)} ${chalk.cyan(d.title)}`);
|
|
48
|
+
console.log(` ${color(rBar)} R=${d.retrievability.toFixed(2)} | ${elapsed}μΌ μ `);
|
|
49
|
+
|
|
50
|
+
const answer = await ask(chalk.dim(' β [y]μ΄κΈ° [n]μ€ν΅ [s]λ΄μΌ λ€μ [q]μ’
λ£: '));
|
|
51
|
+
|
|
52
|
+
if (answer.toLowerCase() === 'q') {
|
|
53
|
+
console.log(chalk.dim('\n리뷰 μ€λ¨.'));
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (answer.toLowerCase() === 's') {
|
|
58
|
+
// Snooze: stabilityλ₯Ό 1μΌλ§ μ΄μ§ μ¬λ €μ λ΄μΌ λ€μ λμ€κ²
|
|
59
|
+
await decayEngine.recordAccess({
|
|
60
|
+
documentId: d.documentId,
|
|
61
|
+
type: 'view',
|
|
62
|
+
timestamp: new Date(Date.now() - 23 * 3600000).toISOString(), // 23μκ° μ μΌλ‘ κΈ°λ‘
|
|
63
|
+
});
|
|
64
|
+
console.log(chalk.dim(' β° λ΄μΌ λ€μ 리λ§μΈλ'));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (answer.toLowerCase() === 'y') {
|
|
69
|
+
// Obsidianμμ μ΄κΈ°
|
|
70
|
+
const relFile = (d as any).filePath
|
|
71
|
+
? (d as any).filePath.replace(/\\/g, '/').replace(/\.md$/, '')
|
|
72
|
+
: d.title;
|
|
73
|
+
|
|
74
|
+
let vault = 'Evan';
|
|
75
|
+
try {
|
|
76
|
+
const doc = db.prepare('SELECT file_path FROM documents WHERE id = ?').get(d.documentId) as any;
|
|
77
|
+
if (doc?.file_path) {
|
|
78
|
+
const fp = doc.file_path.replace(/\\/g, '/').replace(/\.md$/, '');
|
|
79
|
+
// vault μ΄λ¦ = config.vaultPathμ λ§μ§λ§ λλ ν 리λͺ
|
|
80
|
+
vault = config.vaultPath?.replace(/\\/g, '/').replace(/\/$/, '').split('/').pop() ?? 'Evan';
|
|
81
|
+
|
|
82
|
+
const uri = `obsidian://open?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(fp)}`;
|
|
83
|
+
const open = await import('open');
|
|
84
|
+
await open.default(uri);
|
|
85
|
+
}
|
|
86
|
+
} catch { /* fallback: no open */ }
|
|
87
|
+
|
|
88
|
+
// μ κ·Ό κΈ°λ‘ β stability μ
λ°μ΄νΈ
|
|
89
|
+
await decayEngine.recordAccess({
|
|
90
|
+
documentId: d.documentId,
|
|
91
|
+
type: 'view',
|
|
92
|
+
timestamp: new Date().toISOString(),
|
|
93
|
+
});
|
|
94
|
+
reviewed++;
|
|
95
|
+
console.log(chalk.green(' β
μ΄κΈ° + κΈ°μ΅ κ°λ μ
λ°μ΄νΈ'));
|
|
96
|
+
} else {
|
|
97
|
+
console.log(chalk.dim(' βοΈ μ€ν΅'));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
rl.close();
|
|
102
|
+
|
|
103
|
+
console.log(chalk.dim('\nβ'.repeat(50)));
|
|
104
|
+
console.log(chalk.green(`리뷰 μλ£! ${reviewed}/${decaying.length}κ° μ΄λ`));
|
|
105
|
+
|
|
106
|
+
// streak κ³μ° (access_logμμ μ°μ μΌμ)
|
|
107
|
+
try {
|
|
108
|
+
const days = db.prepare(`
|
|
109
|
+
SELECT DISTINCT date(accessed_at) as d FROM access_log
|
|
110
|
+
WHERE access_type = 'view'
|
|
111
|
+
ORDER BY d DESC LIMIT 30
|
|
112
|
+
`).all() as any[];
|
|
113
|
+
|
|
114
|
+
let streak = 0;
|
|
115
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
116
|
+
for (let i = 0; i < days.length; i++) {
|
|
117
|
+
const expected = new Date(Date.now() - i * 86400000).toISOString().slice(0, 10);
|
|
118
|
+
if (days[i]?.d === expected) streak++;
|
|
119
|
+
else break;
|
|
120
|
+
}
|
|
121
|
+
if (streak > 1) {
|
|
122
|
+
console.log(chalk.yellow(`π₯ ${streak}μΌ μ°μ 리뷰!`));
|
|
123
|
+
}
|
|
124
|
+
} catch { /* streak μ€ν¨ν΄λ 무μ */ }
|
|
125
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadConfig, createSqliteVecStore, createLocalEmbedder, createSearchEngine } from '@stellavault/core';
|
|
3
|
+
|
|
4
|
+
export async function searchCommand(query: string, options: { limit?: string }, cmd: any) {
|
|
5
|
+
const globalOpts = cmd?.parent?.opts?.() ?? {};
|
|
6
|
+
const jsonMode = globalOpts.json;
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const limit = parseInt(options.limit ?? '5', 10);
|
|
9
|
+
|
|
10
|
+
const store = createSqliteVecStore(config.dbPath);
|
|
11
|
+
await store.initialize();
|
|
12
|
+
|
|
13
|
+
const embedder = createLocalEmbedder(config.embedding.localModel);
|
|
14
|
+
await embedder.initialize();
|
|
15
|
+
|
|
16
|
+
const engine = createSearchEngine({ store, embedder, rrfK: config.search.rrfK });
|
|
17
|
+
const results = await engine.search({ query, limit });
|
|
18
|
+
|
|
19
|
+
await store.close();
|
|
20
|
+
|
|
21
|
+
if (jsonMode) {
|
|
22
|
+
console.log(JSON.stringify({
|
|
23
|
+
query, count: results.length,
|
|
24
|
+
results: results.map(r => ({
|
|
25
|
+
title: r.document.title, path: r.document.filePath,
|
|
26
|
+
score: r.score, heading: r.chunk.heading,
|
|
27
|
+
snippet: r.chunk.content.slice(0, 200),
|
|
28
|
+
})),
|
|
29
|
+
}, null, 2));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (results.length === 0) {
|
|
34
|
+
console.log(chalk.yellow('κ²μ κ²°κ³Όκ° μμ΅λλ€.'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log('');
|
|
39
|
+
for (let i = 0; i < results.length; i++) {
|
|
40
|
+
const r = results[i];
|
|
41
|
+
console.log(` ${chalk.bold(`${i + 1}.`)} ${chalk.cyan(`[${r.score.toFixed(3)}]`)} ${chalk.white(r.document.filePath)} ${chalk.dim(`Β§${r.chunk.heading}`)}`);
|
|
42
|
+
console.log(` ${chalk.dim(r.chunk.content.slice(0, 120).replace(/\n/g, ' '))}...`);
|
|
43
|
+
}
|
|
44
|
+
console.log('');
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadConfig, createKnowledgeHub } from '@stellavault/core';
|
|
3
|
+
|
|
4
|
+
export async function serveCommand() {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
const hub = createKnowledgeHub(config);
|
|
7
|
+
|
|
8
|
+
await hub.store.initialize();
|
|
9
|
+
await hub.embedder.initialize();
|
|
10
|
+
|
|
11
|
+
const stats = await hub.store.getStats();
|
|
12
|
+
console.error(chalk.green('π MCP Server running (stdio mode)'));
|
|
13
|
+
console.error(`π ${stats.documentCount} documents | ${stats.chunkCount} chunks`);
|
|
14
|
+
console.error(chalk.dim('π‘ Claude Code: claude mcp add stellavault -- stellavault serve'));
|
|
15
|
+
|
|
16
|
+
await hub.mcpServer.startStdio();
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadConfig, createSqliteVecStore } from '@stellavault/core';
|
|
3
|
+
|
|
4
|
+
export async function statusCommand(_opts: any, cmd: any) {
|
|
5
|
+
const globalOpts = cmd?.parent?.opts?.() ?? {};
|
|
6
|
+
const jsonMode = globalOpts.json;
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
|
|
9
|
+
const store = createSqliteVecStore(config.dbPath);
|
|
10
|
+
await store.initialize();
|
|
11
|
+
const stats = await store.getStats();
|
|
12
|
+
const topics = await store.getTopics();
|
|
13
|
+
await store.close();
|
|
14
|
+
|
|
15
|
+
if (jsonMode) {
|
|
16
|
+
console.log(JSON.stringify({ ...stats, vaultPath: config.vaultPath, dbPath: config.dbPath, topics: topics.slice(0, 20) }, null, 2));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.bold('π Stellavault Status'));
|
|
22
|
+
console.log('β'.repeat(40));
|
|
23
|
+
console.log(` π Documents: ${stats.documentCount}`);
|
|
24
|
+
console.log(` π§© Chunks: ${stats.chunkCount}`);
|
|
25
|
+
console.log(` π Last indexed: ${stats.lastIndexed ?? 'never'}`);
|
|
26
|
+
console.log(` πΎ DB: ${config.dbPath}`);
|
|
27
|
+
console.log(` π Vault: ${config.vaultPath || '(not set)'}`);
|
|
28
|
+
|
|
29
|
+
if (topics.length > 0) {
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(chalk.bold('π·οΈ Top topics:'));
|
|
32
|
+
topics.slice(0, 10).forEach((t: any) => {
|
|
33
|
+
console.log(` #${t.topic} (${t.count})`);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
console.log('');
|
|
37
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Design Ref: stellavault sync β NotionβObsidian λκΈ°ν CLI ν΅ν©
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
|
|
8
|
+
export async function syncCommand(options: { upload?: boolean; watch?: boolean }) {
|
|
9
|
+
const syncDir = resolve(process.cwd(), 'packages/sync');
|
|
10
|
+
const syncScript = resolve(syncDir, 'sync-to-obsidian.mjs');
|
|
11
|
+
|
|
12
|
+
if (!existsSync(syncScript)) {
|
|
13
|
+
console.error(chalk.red('β packages/sync/sync-to-obsidian.mjs not found'));
|
|
14
|
+
console.error(chalk.dim(' Run from project root: cd notion-obsidian-sync'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// .env νμΈ
|
|
19
|
+
const envFile = resolve(syncDir, '.env');
|
|
20
|
+
if (!existsSync(envFile)) {
|
|
21
|
+
console.error(chalk.red('β packages/sync/.env not found'));
|
|
22
|
+
console.error(chalk.dim(' Copy .env.example β .env and set NOTION_TOKEN'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (options.upload) {
|
|
27
|
+
// PDCA λ¬Έμ β Notion μ
λ‘λ
|
|
28
|
+
const uploadScript = resolve(syncDir, 'upload-pdca-to-notion.mjs');
|
|
29
|
+
if (!existsSync(uploadScript)) {
|
|
30
|
+
console.error(chalk.red('β upload-pdca-to-notion.mjs not found'));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
console.error(chalk.dim('π€ Uploading PDCA documents to Notion...'));
|
|
34
|
+
await runScript(uploadScript, syncDir);
|
|
35
|
+
} else {
|
|
36
|
+
// Notion β Obsidian λκΈ°ν
|
|
37
|
+
console.error(chalk.dim('π Syncing Notion β Obsidian...'));
|
|
38
|
+
await runScript(syncScript, syncDir);
|
|
39
|
+
|
|
40
|
+
if (options.watch) {
|
|
41
|
+
console.error(chalk.green('π Watch mode β syncing every 5 minutes'));
|
|
42
|
+
setInterval(async () => {
|
|
43
|
+
console.error(chalk.dim(`π [${new Date().toLocaleTimeString()}] Re-syncing...`));
|
|
44
|
+
await runScript(syncScript, syncDir);
|
|
45
|
+
}, 5 * 60 * 1000);
|
|
46
|
+
|
|
47
|
+
// Keep alive
|
|
48
|
+
process.stdin.resume();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function runScript(scriptPath: string, cwd: string): Promise<void> {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const child = spawn('node', [scriptPath], {
|
|
56
|
+
cwd,
|
|
57
|
+
stdio: 'inherit',
|
|
58
|
+
shell: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
child.on('close', (code) => {
|
|
62
|
+
if (code === 0) resolve();
|
|
63
|
+
else reject(new Error(`Script exited with code ${code}`));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
child.on('error', reject);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// sv vault add/list/remove/search-all β Cross-Vault (P3)
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { addVault, removeVault, listVaults, searchAllVaults, loadConfig, createSqliteVecStore, createLocalEmbedder } from '@stellavault/core';
|
|
5
|
+
|
|
6
|
+
export async function vaultAddCommand(id: string, vaultPath: string, options: { name?: string; shared?: boolean }) {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const dbPath = vaultPath.replace(/\/$/, '') + '/.stellavault/index.db';
|
|
9
|
+
try {
|
|
10
|
+
const entry = addVault(id, options.name ?? id, vaultPath, dbPath, !!options.shared);
|
|
11
|
+
console.log(chalk.green(`\n β
Vault "${entry.name}" added (${entry.id})`));
|
|
12
|
+
console.log(chalk.dim(` Path: ${entry.path}\n DB: ${entry.dbPath}\n`));
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.log(chalk.red(`\n β ${err instanceof Error ? err.message : err}\n`));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function vaultListCommand() {
|
|
19
|
+
const vaults = listVaults();
|
|
20
|
+
if (vaults.length === 0) {
|
|
21
|
+
console.log(chalk.yellow('\n No vaults registered. Use: sv vault add <id> <path>\n'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
console.log(chalk.bold('\n Registered Vaults'));
|
|
25
|
+
for (const v of vaults) {
|
|
26
|
+
console.log(` ${chalk.cyan(v.id)} ${v.name} ${chalk.dim(`(${v.path})`)}`);
|
|
27
|
+
}
|
|
28
|
+
console.log('');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function vaultRemoveCommand(id: string) {
|
|
32
|
+
if (removeVault(id)) {
|
|
33
|
+
console.log(chalk.green(`\n β
Vault "${id}" removed\n`));
|
|
34
|
+
} else {
|
|
35
|
+
console.log(chalk.red(`\n β Vault "${id}" not found\n`));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function vaultSearchAllCommand(query: string, options: { limit?: string }) {
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
const embedder = createLocalEmbedder(config.embedding.localModel);
|
|
42
|
+
await embedder.initialize();
|
|
43
|
+
|
|
44
|
+
console.log(chalk.dim(`\n Searching all vaults for "${query}"...`));
|
|
45
|
+
|
|
46
|
+
const results = await searchAllVaults(
|
|
47
|
+
query, embedder,
|
|
48
|
+
(dbPath) => createSqliteVecStore(dbPath),
|
|
49
|
+
{ limit: parseInt(options.limit ?? '10', 10) },
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (results.length === 0) {
|
|
53
|
+
console.log(chalk.yellow(' No results across vaults.\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const r of results) {
|
|
58
|
+
const pct = Math.round(r.score * 100);
|
|
59
|
+
const color = pct >= 70 ? chalk.green : pct >= 40 ? chalk.yellow : chalk.dim;
|
|
60
|
+
console.log(` ${color(`${pct}%`)} ${chalk.bold(r.title)} ${chalk.dim(`[${r.vaultName}]`)}`);
|
|
61
|
+
console.log(` ${chalk.dim(r.snippet)}...`);
|
|
62
|
+
}
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|