stellavault 0.3.0 → 0.4.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/Autonomous_Knowledge_Foundry.pdf +0 -0
- package/CHANGELOG.md +60 -0
- package/README.md +140 -95
- package/package.json +1 -1
- package/packages/cli/dist/commands/ask-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/ask-cmd.js +35 -0
- package/packages/cli/dist/commands/autopilot-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/autopilot-cmd.js +76 -0
- package/packages/cli/dist/commands/compile-cmd.d.ts +6 -0
- package/packages/cli/dist/commands/compile-cmd.js +30 -0
- package/packages/cli/dist/commands/digest-cmd.d.ts +1 -0
- package/packages/cli/dist/commands/digest-cmd.js +57 -0
- package/packages/cli/dist/commands/fleeting-cmd.d.ts +4 -0
- package/packages/cli/dist/commands/fleeting-cmd.js +45 -0
- package/packages/cli/dist/commands/graph-cmd.js +13 -1
- package/packages/cli/dist/commands/ingest-cmd.d.ts +9 -0
- package/packages/cli/dist/commands/ingest-cmd.js +131 -0
- package/packages/cli/dist/commands/init-cmd.js +39 -1
- package/packages/cli/dist/commands/lint-cmd.d.ts +2 -0
- package/packages/cli/dist/commands/lint-cmd.js +61 -0
- package/packages/cli/dist/index.js +46 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/dist/api/server.js +284 -0
- package/packages/core/dist/i18n/note-strings.d.ts +5 -0
- package/packages/core/dist/i18n/note-strings.js +94 -0
- package/packages/core/dist/index.d.ts +9 -0
- package/packages/core/dist/index.js +5 -0
- package/packages/core/dist/intelligence/ask-engine.d.ts +23 -0
- package/packages/core/dist/intelligence/ask-engine.js +108 -0
- package/packages/core/dist/intelligence/ingest-pipeline.d.ts +31 -0
- package/packages/core/dist/intelligence/ingest-pipeline.js +192 -0
- package/packages/core/dist/intelligence/knowledge-lint.d.ts +27 -0
- package/packages/core/dist/intelligence/knowledge-lint.js +132 -0
- package/packages/core/dist/intelligence/wiki-compiler.d.ts +30 -0
- package/packages/core/dist/intelligence/wiki-compiler.js +222 -0
- package/packages/core/dist/intelligence/youtube-extractor.d.ts +29 -0
- package/packages/core/dist/intelligence/youtube-extractor.js +311 -0
- package/packages/core/dist/intelligence/zettelkasten.d.ts +59 -0
- package/packages/core/dist/intelligence/zettelkasten.js +234 -0
- package/packages/core/dist/mcp/server.d.ts +2 -0
- package/packages/core/dist/mcp/server.js +18 -1
- package/packages/core/dist/mcp/tools/agentic-graph.d.ts +6 -0
- package/packages/core/dist/mcp/tools/agentic-graph.js +35 -7
- package/packages/core/dist/mcp/tools/ask.d.ts +29 -0
- package/packages/core/dist/mcp/tools/ask.js +40 -0
- package/packages/core/package.json +5 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// stellavault fleeting — 찰나 메모 즉시 캡처
|
|
2
|
+
// "떠오른 생각을 raw/ 폴더에 즉시 저장"
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { loadConfig } from '@stellavault/core';
|
|
5
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
6
|
+
import { join, resolve } from 'node:path';
|
|
7
|
+
export async function fleetingCommand(text, options) {
|
|
8
|
+
if (!text || text.trim().length < 2) {
|
|
9
|
+
console.error(chalk.yellow('Usage: stellavault fleeting "your idea here" [--tags tag1,tag2]'));
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const rawDir = resolve(config.vaultPath, 'raw');
|
|
14
|
+
if (!existsSync(rawDir))
|
|
15
|
+
mkdirSync(rawDir, { recursive: true });
|
|
16
|
+
const now = new Date();
|
|
17
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
18
|
+
const slug = text.slice(0, 40).replace(/[^a-zA-Z0-9가-힣\s]/g, '').replace(/\s+/g, '-').toLowerCase();
|
|
19
|
+
const filename = `${timestamp}-${slug}.md`;
|
|
20
|
+
const filePath = join(rawDir, filename);
|
|
21
|
+
// path traversal 방지
|
|
22
|
+
if (!resolve(filePath).startsWith(resolve(rawDir))) {
|
|
23
|
+
console.error(chalk.red('Invalid file path'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const tags = options.tags ? options.tags.split(',').map(t => t.trim()) : [];
|
|
27
|
+
const content = [
|
|
28
|
+
'---',
|
|
29
|
+
`title: "${text.slice(0, 80)}"`,
|
|
30
|
+
'type: fleeting',
|
|
31
|
+
`created: ${now.toISOString()}`,
|
|
32
|
+
`tags: [${tags.map(t => `"${t}"`).join(', ')}]`,
|
|
33
|
+
'---',
|
|
34
|
+
'',
|
|
35
|
+
text,
|
|
36
|
+
'',
|
|
37
|
+
'---',
|
|
38
|
+
`*Captured via \`stellavault fleeting\` at ${now.toLocaleString('ko-KR')}*`,
|
|
39
|
+
].join('\n');
|
|
40
|
+
writeFileSync(filePath, content, 'utf-8');
|
|
41
|
+
console.log(chalk.green(`Captured: ${filename}`));
|
|
42
|
+
console.log(chalk.dim(`Location: raw/${filename}`));
|
|
43
|
+
console.log(chalk.dim('Run `stellavault compile` to process into wiki.'));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=fleeting-cmd.js.map
|
|
@@ -27,8 +27,20 @@ export async function graphCommand() {
|
|
|
27
27
|
searchEngine: hub.searchEngine,
|
|
28
28
|
port,
|
|
29
29
|
vaultName,
|
|
30
|
+
vaultPath: config.vaultPath,
|
|
30
31
|
});
|
|
31
|
-
|
|
32
|
+
try {
|
|
33
|
+
await api.start();
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err?.code === 'EADDRINUSE') {
|
|
37
|
+
console.error(chalk.red(`Port ${port} is already in use.`));
|
|
38
|
+
console.error(chalk.dim(`Stop the other process or use a different port:`));
|
|
39
|
+
console.error(chalk.dim(` Edit .stellavault.json: { "mcp": { "port": ${port + 1} } }`));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
32
44
|
console.error(chalk.green('🧠 Stellavault — Neural Knowledge Graph'));
|
|
33
45
|
console.error(` 📚 ${stats.documentCount} documents | ${stats.chunkCount} chunks`);
|
|
34
46
|
console.error(` 🌐 API: http://127.0.0.1:${port}`);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function ingestCommand(input: string, options: {
|
|
2
|
+
tags?: string;
|
|
3
|
+
stage?: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function promoteCommand(filePath: string, options: {
|
|
7
|
+
to: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=ingest-cmd.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// stellavault ingest — 통합 인제스트 (URL, 텍스트, 파일 → 자동 분류 저장)
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { loadConfig, ingest, promoteNote } from '@stellavault/core';
|
|
4
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { extname } from 'node:path';
|
|
6
|
+
export async function ingestCommand(input, options) {
|
|
7
|
+
if (!input) {
|
|
8
|
+
console.error(chalk.yellow('Usage: stellavault ingest <url|file|text> [--tags t1,t2] [--stage fleeting|literature|permanent]'));
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
const tags = options.tags?.split(',').map(t => t.trim()) ?? [];
|
|
13
|
+
const stage = (options.stage ?? 'fleeting');
|
|
14
|
+
// 입력 타입 감지
|
|
15
|
+
let ingestInput;
|
|
16
|
+
if (/^https?:\/\//.test(input)) {
|
|
17
|
+
// URL
|
|
18
|
+
const isYouTube = /youtube\.com\/watch|youtu\.be\//.test(input);
|
|
19
|
+
// SSRF 방지: private IP 차단
|
|
20
|
+
try {
|
|
21
|
+
const url = new URL(input);
|
|
22
|
+
const host = url.hostname;
|
|
23
|
+
if (/^(127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|0\.|localhost|::1)/i.test(host)) {
|
|
24
|
+
console.error(chalk.yellow('Private/local URLs are not allowed for security.'));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch { /* invalid URL, will fail at fetch */ }
|
|
29
|
+
if (isYouTube) {
|
|
30
|
+
// YouTube: 전용 추출기 사용 (메타데이터 + 자막 + 타임스탬프)
|
|
31
|
+
try {
|
|
32
|
+
const { extractYouTubeContent, formatYouTubeNote } = await import('@stellavault/core/intelligence/youtube-extractor');
|
|
33
|
+
const ytContent = await extractYouTubeContent(input);
|
|
34
|
+
const body = formatYouTubeNote(ytContent);
|
|
35
|
+
ingestInput = {
|
|
36
|
+
type: 'youtube',
|
|
37
|
+
content: input + '\n' + body,
|
|
38
|
+
tags: [...tags, ...ytContent.tags.filter((t) => !tags.includes(t))],
|
|
39
|
+
stage: stage === 'fleeting' ? 'literature' : stage, // YouTube는 literature로 자동 승격
|
|
40
|
+
title: options.title ?? ytContent.title,
|
|
41
|
+
source: input,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error(chalk.yellow(`YouTube extraction failed, falling back to basic URL. (${err instanceof Error ? err.message : 'error'})`));
|
|
46
|
+
ingestInput = {
|
|
47
|
+
type: 'youtube',
|
|
48
|
+
content: input + '\n',
|
|
49
|
+
tags,
|
|
50
|
+
stage,
|
|
51
|
+
title: options.title,
|
|
52
|
+
source: input,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// 일반 URL: HTML → 텍스트 변환
|
|
58
|
+
let content = input + '\n';
|
|
59
|
+
try {
|
|
60
|
+
const resp = await fetch(input);
|
|
61
|
+
const html = await resp.text();
|
|
62
|
+
const text = html
|
|
63
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
64
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
65
|
+
.replace(/<[^>]+>/g, ' ')
|
|
66
|
+
.replace(/ /g, ' ')
|
|
67
|
+
.replace(/\s+/g, ' ')
|
|
68
|
+
.trim()
|
|
69
|
+
.slice(0, 5000);
|
|
70
|
+
content += text;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
console.error(chalk.yellow(`Web fetch failed: saving URL only. (${err instanceof Error ? err.message : 'network error'})`));
|
|
74
|
+
}
|
|
75
|
+
ingestInput = {
|
|
76
|
+
type: 'url',
|
|
77
|
+
content,
|
|
78
|
+
tags,
|
|
79
|
+
stage,
|
|
80
|
+
title: options.title,
|
|
81
|
+
source: input,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (existsSync(input)) {
|
|
86
|
+
// 파일
|
|
87
|
+
const ext = extname(input).toLowerCase();
|
|
88
|
+
const fileContent = readFileSync(input, 'utf-8');
|
|
89
|
+
ingestInput = {
|
|
90
|
+
type: ext === '.pdf' ? 'pdf-text' : 'file',
|
|
91
|
+
content: fileContent,
|
|
92
|
+
tags,
|
|
93
|
+
stage,
|
|
94
|
+
title: options.title,
|
|
95
|
+
source: input,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// 플레인 텍스트
|
|
100
|
+
ingestInput = {
|
|
101
|
+
type: 'text',
|
|
102
|
+
content: input,
|
|
103
|
+
tags,
|
|
104
|
+
stage,
|
|
105
|
+
title: options.title,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const result = ingest(config.vaultPath, ingestInput);
|
|
109
|
+
console.log(chalk.green(`Ingested: ${result.title}`));
|
|
110
|
+
console.log(chalk.dim(` Stage: ${result.stage}`));
|
|
111
|
+
console.log(chalk.dim(` Saved: ${result.savedTo}`));
|
|
112
|
+
console.log(chalk.dim(` Words: ${result.wordCount}`));
|
|
113
|
+
if (result.indexCode)
|
|
114
|
+
console.log(chalk.dim(` Index: ${result.indexCode}`));
|
|
115
|
+
if (result.tags.length > 0)
|
|
116
|
+
console.log(chalk.dim(` Tags: ${result.tags.join(', ')}`));
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(chalk.dim('Run `stellavault compile` to process into wiki.'));
|
|
119
|
+
console.log(chalk.dim('Run `stellavault autopilot` for full pipeline.'));
|
|
120
|
+
}
|
|
121
|
+
export async function promoteCommand(filePath, options) {
|
|
122
|
+
const config = loadConfig();
|
|
123
|
+
const target = options.to;
|
|
124
|
+
if (!['fleeting', 'literature', 'permanent'].includes(target)) {
|
|
125
|
+
console.error(chalk.red('--to must be: fleeting, literature, or permanent'));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const newPath = promoteNote(config.vaultPath, filePath, target);
|
|
129
|
+
console.log(chalk.green(`Promoted to ${target}: ${newPath}`));
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=ingest-cmd.js.map
|
|
@@ -56,7 +56,7 @@ export async function initCommand() {
|
|
|
56
56
|
console.log('');
|
|
57
57
|
console.log(chalk.cyan(' Step 2/3') + ' — Indexing your vault');
|
|
58
58
|
console.log(chalk.dim(' Vectorizing notes with local AI (no data leaves your machine).\n'));
|
|
59
|
-
const spinner = ora({ text: ' Loading embedding model...', indent: 2 }).start();
|
|
59
|
+
const spinner = ora({ text: ' Loading embedding model (first run downloads ~30MB, please wait)...', indent: 2 }).start();
|
|
60
60
|
const store = createSqliteVecStore(dbPath);
|
|
61
61
|
await store.initialize();
|
|
62
62
|
const embedder = createLocalEmbedder('all-MiniLM-L6-v2');
|
|
@@ -113,6 +113,44 @@ export async function initCommand() {
|
|
|
113
113
|
console.log(` ${chalk.cyan('stellavault brief')} Get your daily knowledge briefing`);
|
|
114
114
|
console.log(` ${chalk.cyan('stellavault serve')} Connect AI agents via MCP`);
|
|
115
115
|
console.log('');
|
|
116
|
+
// Day 2 Experience — 습관화 제안
|
|
117
|
+
console.log(chalk.cyan(' ─── Build a habit ───\n'));
|
|
118
|
+
const setupCron = await ask(rl, ' Auto-run daily briefing? (adds cron job) [Y/n]', 'Y');
|
|
119
|
+
if (setupCron.toLowerCase() !== 'n') {
|
|
120
|
+
const cronLine = `0 9 * * * cd "${vaultPath}" && stellavault brief >> ~/.stellavault/daily.log 2>&1`;
|
|
121
|
+
const platform = process.platform;
|
|
122
|
+
if (platform === 'win32') {
|
|
123
|
+
console.log(chalk.dim('\n Windows: Add this to Task Scheduler:'));
|
|
124
|
+
console.log(chalk.dim(` Action: stellavault brief`));
|
|
125
|
+
console.log(chalk.dim(` Trigger: Daily at 9:00 AM`));
|
|
126
|
+
console.log(chalk.dim(` Start in: ${vaultPath}\n`));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(chalk.dim('\n Add this to your crontab (crontab -e):'));
|
|
130
|
+
console.log(chalk.dim(` ${cronLine}\n`));
|
|
131
|
+
const autoAdd = await ask(rl, ' Add to crontab now? [Y/n]', 'Y');
|
|
132
|
+
if (autoAdd.toLowerCase() !== 'n') {
|
|
133
|
+
try {
|
|
134
|
+
const { execSync } = await import('node:child_process');
|
|
135
|
+
const existing = execSync('crontab -l 2>/dev/null || true', { encoding: 'utf-8' });
|
|
136
|
+
if (!existing.includes('stellavault brief')) {
|
|
137
|
+
execSync(`(crontab -l 2>/dev/null; echo "${cronLine}") | crontab -`, { encoding: 'utf-8' });
|
|
138
|
+
console.log(chalk.green(' ✓ Daily briefing scheduled at 9:00 AM\n'));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.log(chalk.dim(' Already scheduled.\n'));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
console.log(chalk.yellow(' Could not auto-add. Please add manually.\n'));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
console.log(chalk.dim(' Tomorrow morning, run:'));
|
|
151
|
+
console.log(` ${chalk.cyan('stellavault brief')} See what changed overnight`);
|
|
152
|
+
console.log(` ${chalk.cyan('stellavault decay')} Review fading knowledge`);
|
|
153
|
+
console.log('');
|
|
116
154
|
console.log(chalk.dim(' Your knowledge is now alive. ✦'));
|
|
117
155
|
console.log('');
|
|
118
156
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// stellavault lint — 지식 건강 검사 CLI
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { loadConfig, createKnowledgeHub, lintKnowledge } from '@stellavault/core';
|
|
4
|
+
export async function lintCommand() {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
const hub = createKnowledgeHub(config);
|
|
7
|
+
console.error(chalk.dim('Scanning your knowledge base...'));
|
|
8
|
+
await hub.store.initialize();
|
|
9
|
+
const result = await lintKnowledge(hub.store);
|
|
10
|
+
// 건강도 점수
|
|
11
|
+
const scoreColor = result.score >= 80 ? chalk.green : result.score >= 50 ? chalk.yellow : chalk.red;
|
|
12
|
+
console.log('');
|
|
13
|
+
console.log(chalk.bold('Knowledge Health Report'));
|
|
14
|
+
console.log('─'.repeat(40));
|
|
15
|
+
console.log(`Score: ${scoreColor(result.score + '/100')}`);
|
|
16
|
+
console.log(`Documents: ${result.stats.totalDocs}`);
|
|
17
|
+
console.log('');
|
|
18
|
+
// 이슈
|
|
19
|
+
if (result.issues.length > 0) {
|
|
20
|
+
const critical = result.issues.filter(i => i.severity === 'critical');
|
|
21
|
+
const warnings = result.issues.filter(i => i.severity === 'warning');
|
|
22
|
+
const info = result.issues.filter(i => i.severity === 'info');
|
|
23
|
+
if (critical.length > 0) {
|
|
24
|
+
console.log(chalk.red(`Critical: ${critical.length}`));
|
|
25
|
+
for (const i of critical) {
|
|
26
|
+
console.log(chalk.red(` ✗ ${i.message}`));
|
|
27
|
+
if (i.suggestion)
|
|
28
|
+
console.log(chalk.dim(` → ${i.suggestion}`));
|
|
29
|
+
}
|
|
30
|
+
console.log('');
|
|
31
|
+
}
|
|
32
|
+
if (warnings.length > 0) {
|
|
33
|
+
console.log(chalk.yellow(`Warnings: ${warnings.length}`));
|
|
34
|
+
for (const i of warnings.slice(0, 10)) {
|
|
35
|
+
console.log(chalk.yellow(` ! ${i.message}`));
|
|
36
|
+
if (i.suggestion)
|
|
37
|
+
console.log(chalk.dim(` → ${i.suggestion}`));
|
|
38
|
+
}
|
|
39
|
+
if (warnings.length > 10)
|
|
40
|
+
console.log(chalk.dim(` ... and ${warnings.length - 10} more`));
|
|
41
|
+
console.log('');
|
|
42
|
+
}
|
|
43
|
+
if (info.length > 0) {
|
|
44
|
+
console.log(chalk.dim(`Info: ${info.length}`));
|
|
45
|
+
for (const i of info.slice(0, 5)) {
|
|
46
|
+
console.log(chalk.dim(` ℹ ${i.message}`));
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 제안
|
|
52
|
+
if (result.suggestions.length > 0) {
|
|
53
|
+
console.log(chalk.cyan('Suggestions:'));
|
|
54
|
+
for (const s of result.suggestions) {
|
|
55
|
+
console.log(` → ${s}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
console.log('');
|
|
59
|
+
await hub.store.close?.();
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=lint-cmd.js.map
|
|
@@ -21,11 +21,17 @@ import { federateJoinCommand, federateStatusCommand } from './commands/federate-
|
|
|
21
21
|
import { cloudSyncCommand, cloudRestoreCommand, cloudStatusCommand } from './commands/cloud-cmd.js';
|
|
22
22
|
import { vaultAddCommand, vaultListCommand, vaultRemoveCommand, vaultSearchAllCommand } from './commands/vault-cmd.js';
|
|
23
23
|
import { captureCommand } from './commands/capture-cmd.js';
|
|
24
|
+
import { askCommand } from './commands/ask-cmd.js';
|
|
25
|
+
import { compileCommand } from './commands/compile-cmd.js';
|
|
26
|
+
import { lintCommand } from './commands/lint-cmd.js';
|
|
27
|
+
import { fleetingCommand } from './commands/fleeting-cmd.js';
|
|
28
|
+
import { ingestCommand, promoteCommand } from './commands/ingest-cmd.js';
|
|
29
|
+
import { autopilotCommand } from './commands/autopilot-cmd.js';
|
|
24
30
|
const program = new Command();
|
|
25
31
|
program
|
|
26
32
|
.name('stellavault')
|
|
27
33
|
.description('Stellavault — Turn your Obsidian vault into a 3D neural knowledge graph')
|
|
28
|
-
.version('0.
|
|
34
|
+
.version('0.3.0')
|
|
29
35
|
.option('--json', 'Output in JSON format (for scripting)')
|
|
30
36
|
.option('--quiet', 'Suppress non-essential output');
|
|
31
37
|
program
|
|
@@ -78,6 +84,7 @@ program
|
|
|
78
84
|
.command('digest')
|
|
79
85
|
.description('주간 지식 활동 리포트')
|
|
80
86
|
.option('-d, --days <n>', '기간 (일)', '7')
|
|
87
|
+
.option('-v, --visual', 'Save as .md with Mermaid charts for Obsidian')
|
|
81
88
|
.action(digestCommand);
|
|
82
89
|
program
|
|
83
90
|
.command('clip <url>')
|
|
@@ -120,6 +127,44 @@ program
|
|
|
120
127
|
.option('-t, --tags <tags>', 'Comma-separated tags')
|
|
121
128
|
.option('-f, --folder <folder>', 'Vault subfolder', '01_Knowledge/voice')
|
|
122
129
|
.action(captureCommand);
|
|
130
|
+
program
|
|
131
|
+
.command('ask <question>')
|
|
132
|
+
.description('Ask a question about your knowledge base — search, compose answer, optionally save')
|
|
133
|
+
.option('-s, --save', 'Save answer as a new note in your vault')
|
|
134
|
+
.action((question, opts) => askCommand(question, opts));
|
|
135
|
+
program
|
|
136
|
+
.command('compile')
|
|
137
|
+
.description('Compile raw/ documents into a structured wiki')
|
|
138
|
+
.option('-r, --raw <dir>', 'Raw documents directory (default: raw/)')
|
|
139
|
+
.option('-w, --wiki <dir>', 'Wiki output directory (default: _wiki/)')
|
|
140
|
+
.option('-f, --force', 'Overwrite existing wiki files')
|
|
141
|
+
.action((opts) => compileCommand(opts));
|
|
142
|
+
program
|
|
143
|
+
.command('lint')
|
|
144
|
+
.description('Knowledge health check — find gaps, duplicates, contradictions, stale notes')
|
|
145
|
+
.action(() => lintCommand());
|
|
146
|
+
program
|
|
147
|
+
.command('fleeting <text>')
|
|
148
|
+
.description('Capture a fleeting idea instantly to raw/ folder')
|
|
149
|
+
.option('-t, --tags <tags>', 'Comma-separated tags')
|
|
150
|
+
.action((text, opts) => fleetingCommand(text, opts));
|
|
151
|
+
program
|
|
152
|
+
.command('ingest <input>')
|
|
153
|
+
.description('Ingest any input (URL, file, text) into your knowledge base')
|
|
154
|
+
.option('-t, --tags <tags>', 'Comma-separated tags')
|
|
155
|
+
.option('-s, --stage <stage>', 'Note stage: fleeting, literature, permanent', 'fleeting')
|
|
156
|
+
.option('--title <title>', 'Override title')
|
|
157
|
+
.action((input, opts) => ingestCommand(input, opts));
|
|
158
|
+
program
|
|
159
|
+
.command('promote <file>')
|
|
160
|
+
.description('Promote a note: fleeting → literature → permanent')
|
|
161
|
+
.requiredOption('--to <stage>', 'Target stage: literature or permanent')
|
|
162
|
+
.action((file, opts) => promoteCommand(file, opts));
|
|
163
|
+
program
|
|
164
|
+
.command('autopilot')
|
|
165
|
+
.description('Run the full knowledge flywheel: inbox → compile → lint')
|
|
166
|
+
.option('--once', 'Run once (default)')
|
|
167
|
+
.action((opts) => autopilotCommand(opts));
|
|
123
168
|
const vault = program.command('vault').description('Multi-Vault — manage and search across vaults');
|
|
124
169
|
vault.command('add <id> <path>').description('Register a vault').option('-n, --name <name>', 'Display name').option('-s, --shared', 'Allow federation sharing').action(vaultAddCommand);
|
|
125
170
|
vault.command('list').description('List registered vaults').action(vaultListCommand);
|