clawvault 2.5.2 → 2.5.4
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/README.md +159 -200
- package/bin/clawvault.js +111 -111
- package/bin/command-registration.test.js +166 -166
- package/bin/command-runtime.js +93 -93
- package/bin/command-runtime.test.js +154 -154
- package/bin/help-contract.test.js +39 -39
- package/bin/register-config-commands.js +153 -153
- package/bin/register-config-route-commands.test.js +121 -121
- package/bin/register-core-commands.js +237 -237
- package/bin/register-kanban-commands.js +56 -56
- package/bin/register-kanban-commands.test.js +83 -83
- package/bin/register-maintenance-commands.js +282 -282
- package/bin/register-project-commands.js +209 -209
- package/bin/register-project-commands.test.js +206 -206
- package/bin/register-query-commands.js +317 -317
- package/bin/register-query-commands.test.js +65 -65
- package/bin/register-resilience-commands.js +182 -182
- package/bin/register-resilience-commands.test.js +81 -81
- package/bin/register-route-commands.js +114 -114
- package/bin/register-session-lifecycle-commands.js +206 -206
- package/bin/register-tailscale-commands.js +106 -106
- package/bin/register-task-commands.js +348 -348
- package/bin/register-task-commands.test.js +69 -69
- package/bin/register-template-commands.js +72 -72
- package/bin/register-vault-operations-commands.js +300 -300
- package/bin/test-helpers/cli-command-fixtures.js +119 -119
- package/dashboard/lib/graph-diff.js +104 -104
- package/dashboard/lib/graph-diff.test.js +75 -75
- package/dashboard/lib/vault-parser.js +556 -556
- package/dashboard/lib/vault-parser.test.js +254 -254
- package/dashboard/public/app.js +796 -796
- package/dashboard/public/index.html +52 -52
- package/dashboard/public/styles.css +221 -221
- package/dashboard/server.js +374 -374
- package/dist/{chunk-3FP5BJ42.js → chunk-4QYGFWRM.js} +1 -1
- package/dist/{chunk-M25QVSJM.js → chunk-AXKYDCNN.js} +1 -1
- package/dist/{chunk-CLE2HHNT.js → chunk-IVRIKYFE.js} +18 -11
- package/dist/{chunk-HRTPQQF2.js → chunk-IZEY5S74.js} +1 -1
- package/dist/{chunk-HWUNREDJ.js → chunk-JDLOL2PL.js} +4 -4
- package/dist/{chunk-AY4PGUVL.js → chunk-KL4NAOMO.js} +1 -1
- package/dist/{chunk-O7XHXF7F.js → chunk-MAKNAHAW.js} +4 -4
- package/dist/{chunk-PLZKZW4I.js → chunk-OSMS7QIG.js} +1 -1
- package/dist/{chunk-NZ4ZZNSR.js → chunk-THRJVD4L.js} +1 -1
- package/dist/{chunk-4GBPTBFJ.js → chunk-TIGW564L.js} +1 -1
- package/dist/{chunk-BHO7WSAY.js → chunk-W2HNZC22.js} +3 -3
- package/dist/{chunk-GFJ3LIIB.js → chunk-XAVB4GB4.js} +1 -1
- package/dist/cli/index.js +10 -10
- package/dist/commands/context.js +3 -3
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/embed.js +2 -2
- package/dist/commands/observe.js +2 -2
- package/dist/commands/setup.js +2 -2
- package/dist/commands/sleep.js +2 -2
- package/dist/commands/status.js +3 -3
- package/dist/commands/tailscale.js +3 -3
- package/dist/commands/wake.js +2 -2
- package/dist/index.js +12 -12
- package/dist/lib/tailscale.js +2 -2
- package/dist/lib/webdav.js +1 -1
- package/hooks/clawvault/HOOK.md +83 -74
- package/hooks/clawvault/handler.js +816 -816
- package/hooks/clawvault/handler.test.js +263 -263
- package/package.json +94 -125
- package/templates/checkpoint.md +19 -19
- package/templates/daily-note.md +19 -19
- package/templates/daily.md +19 -19
- package/templates/decision.md +17 -17
- package/templates/handoff.md +19 -19
- package/templates/lesson.md +16 -16
- package/templates/person.md +19 -19
- package/templates/project.md +23 -23
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core vault lifecycle and write command registrations.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { validatePathWithinBase } from './command-runtime.js';
|
|
6
|
-
|
|
7
|
-
export function registerCoreCommands(
|
|
8
|
-
program,
|
|
9
|
-
{ chalk, path, fs, createVault, getVault, runQmd }
|
|
10
|
-
) {
|
|
11
|
-
// === INIT ===
|
|
12
|
-
program
|
|
13
|
-
.command('init [path]')
|
|
14
|
-
.description('Initialize a new ClawVault vault')
|
|
15
|
-
.option('-n, --name <name>', 'Vault name (default: target directory name)')
|
|
16
|
-
.option('--qmd', 'Set up qmd semantic search collection')
|
|
17
|
-
.option('--qmd-collection <name>', 'qmd collection name (defaults to vault name)')
|
|
18
|
-
.option('--no-bases', 'Skip Obsidian Bases file generation')
|
|
19
|
-
.option('--no-tasks', 'Skip tasks/ and backlog/ directories')
|
|
20
|
-
.option('--no-graph', 'Skip initial graph build')
|
|
21
|
-
.option('--categories <list>', 'Comma-separated list of custom categories to create')
|
|
22
|
-
.option('--canvas', 'Generate a vault status canvas dashboard on init')
|
|
23
|
-
.option('--theme <style>', 'Graph color theme to apply (neural, minimal, none) (default: none)', 'none')
|
|
24
|
-
.option('--minimal', 'Create minimal vault (memory categories only, no tasks/bases/graph)')
|
|
25
|
-
.action(async (vaultPath, options) => {
|
|
26
|
-
const targetPath = vaultPath || '.';
|
|
27
|
-
const resolvedPath = path.resolve(targetPath);
|
|
28
|
-
console.log(chalk.cyan(`\n🐘 Initializing ClawVault at ${resolvedPath}...\n`));
|
|
29
|
-
|
|
30
|
-
// Check for existing vault
|
|
31
|
-
const existingConfig = path.join(resolvedPath, '.clawvault.json');
|
|
32
|
-
if (fs.existsSync(existingConfig)) {
|
|
33
|
-
console.error(chalk.red(`Error: A ClawVault already exists at ${resolvedPath}`));
|
|
34
|
-
console.error(chalk.dim(' Use --force to reinitialize (not yet supported) or choose a different path.'));
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
// Resolve --minimal shorthand
|
|
40
|
-
const isMinimal = !!options.minimal;
|
|
41
|
-
const skipBases = isMinimal || options.bases === false;
|
|
42
|
-
const skipTasks = isMinimal || !!options.noTasks;
|
|
43
|
-
const skipGraph = isMinimal || !!options.noGraph;
|
|
44
|
-
|
|
45
|
-
// Resolve custom categories
|
|
46
|
-
const { DEFAULT_CATEGORIES } = await import('../dist/index.js');
|
|
47
|
-
let categories = [...DEFAULT_CATEGORIES];
|
|
48
|
-
if (options.categories) {
|
|
49
|
-
const customCats = options.categories.split(',').map(c => c.trim()).filter(Boolean);
|
|
50
|
-
categories = customCats;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const vault = await createVault(targetPath, {
|
|
54
|
-
name: options.name || path.basename(resolvedPath),
|
|
55
|
-
qmdCollection: options.qmdCollection,
|
|
56
|
-
categories
|
|
57
|
-
}, { skipBases, skipTasks, skipGraph });
|
|
58
|
-
|
|
59
|
-
const vaultCategories = vault.getCategories();
|
|
60
|
-
const memoryCategories = vaultCategories.filter(c => !['templates', 'tasks', 'backlog'].includes(c));
|
|
61
|
-
const workCategories = vaultCategories.filter(c => ['tasks', 'backlog'].includes(c));
|
|
62
|
-
|
|
63
|
-
console.log(chalk.green('✓ Vault created'));
|
|
64
|
-
console.log(chalk.dim(` Memory: ${memoryCategories.join(', ')}`));
|
|
65
|
-
if (workCategories.length > 0) {
|
|
66
|
-
console.log(chalk.dim(` Work: ${workCategories.join(', ')}`));
|
|
67
|
-
}
|
|
68
|
-
console.log(chalk.dim(` Ledger: ledger/raw, ledger/observations, ledger/reflections`));
|
|
69
|
-
if (skipBases) console.log(chalk.dim(' Bases: skipped'));
|
|
70
|
-
if (skipGraph) console.log(chalk.dim(' Graph: skipped'));
|
|
71
|
-
|
|
72
|
-
console.log(chalk.cyan('\nSetting up qmd collection...'));
|
|
73
|
-
try {
|
|
74
|
-
await runQmd([
|
|
75
|
-
'collection',
|
|
76
|
-
'add',
|
|
77
|
-
vault.getQmdRoot(),
|
|
78
|
-
'--name',
|
|
79
|
-
vault.getQmdCollection(),
|
|
80
|
-
'--mask',
|
|
81
|
-
'**/*.md'
|
|
82
|
-
]);
|
|
83
|
-
console.log(chalk.green('✓ qmd collection created'));
|
|
84
|
-
} catch {
|
|
85
|
-
console.log(chalk.yellow('⚠ qmd collection may already exist'));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Apply theme if requested
|
|
89
|
-
if (options.theme && options.theme !== 'none') {
|
|
90
|
-
try {
|
|
91
|
-
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
92
|
-
await setupCommand({
|
|
93
|
-
graphColors: true,
|
|
94
|
-
bases: false,
|
|
95
|
-
canvas: false,
|
|
96
|
-
theme: options.theme,
|
|
97
|
-
vault: resolvedPath
|
|
98
|
-
});
|
|
99
|
-
} catch {
|
|
100
|
-
console.log(chalk.yellow(`⚠ Could not apply ${options.theme} theme`));
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Generate canvas if requested
|
|
105
|
-
if (options.canvas) {
|
|
106
|
-
try {
|
|
107
|
-
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
108
|
-
await setupCommand({
|
|
109
|
-
graphColors: false,
|
|
110
|
-
bases: false,
|
|
111
|
-
canvas: true,
|
|
112
|
-
theme: 'none',
|
|
113
|
-
vault: resolvedPath
|
|
114
|
-
});
|
|
115
|
-
} catch {
|
|
116
|
-
console.log(chalk.yellow(`⚠ Could not generate canvas`));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.log(chalk.green('\n✅ ClawVault ready!\n'));
|
|
121
|
-
console.log(' ' + chalk.bold('Try these:'));
|
|
122
|
-
console.log(chalk.dim(' clawvault capture "my first thought" # quick capture'));
|
|
123
|
-
console.log(chalk.dim(' clawvault graph # see your knowledge graph'));
|
|
124
|
-
console.log(chalk.dim(' clawvault context "topic" # graph-aware context'));
|
|
125
|
-
console.log(chalk.dim(' clawvault checkpoint --working-on "task" # save progress'));
|
|
126
|
-
console.log();
|
|
127
|
-
console.log(chalk.dim(' Full docs: https://docs.clawvault.dev'));
|
|
128
|
-
console.log();
|
|
129
|
-
} catch (err) {
|
|
130
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// === SETUP ===
|
|
136
|
-
program
|
|
137
|
-
.command('setup')
|
|
138
|
-
.description('Auto-discover and configure an existing ClawVault vault')
|
|
139
|
-
.option('--graph-colors', 'Set up graph color scheme for Obsidian')
|
|
140
|
-
.option('--no-graph-colors', 'Skip graph color configuration')
|
|
141
|
-
.option('--bases', 'Generate Obsidian Bases views for task management')
|
|
142
|
-
.option('--no-bases', 'Skip Bases file generation')
|
|
143
|
-
.option('--canvas', 'Generate vault status canvas dashboard')
|
|
144
|
-
.option('--no-canvas', 'Skip canvas generation')
|
|
145
|
-
.option('--theme <style>', 'Graph color theme (neural, minimal, none) (default: neural)', 'neural')
|
|
146
|
-
.option('--force', 'Overwrite existing configuration files')
|
|
147
|
-
.option('-v, --vault <path>', 'Vault path')
|
|
148
|
-
.action(async (options) => {
|
|
149
|
-
try {
|
|
150
|
-
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
151
|
-
await setupCommand({
|
|
152
|
-
graphColors: options.graphColors,
|
|
153
|
-
bases: options.bases,
|
|
154
|
-
canvas: options.canvas,
|
|
155
|
-
theme: options.theme,
|
|
156
|
-
force: options.force,
|
|
157
|
-
vault: options.vault
|
|
158
|
-
});
|
|
159
|
-
} catch (err) {
|
|
160
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// === STORE ===
|
|
166
|
-
program
|
|
167
|
-
.command('store')
|
|
168
|
-
.description('Store a new memory document')
|
|
169
|
-
.requiredOption('-c, --category <category>', 'Category (preferences, decisions, patterns, people, projects, goals, transcripts, inbox)')
|
|
170
|
-
.requiredOption('-t, --title <title>', 'Document title')
|
|
171
|
-
.option('--content <content>', 'Content body')
|
|
172
|
-
.option('-f, --file <file>', 'Read content from file (validated against current working directory)')
|
|
173
|
-
.option('--stdin', 'Read content from stdin')
|
|
174
|
-
.option('--overwrite', 'Overwrite if exists')
|
|
175
|
-
.option('--no-index', 'Skip qmd index update (auto-updates by default)')
|
|
176
|
-
.option('--embed', 'Also update qmd embeddings for vector search')
|
|
177
|
-
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
178
|
-
.action(async (options) => {
|
|
179
|
-
try {
|
|
180
|
-
const vault = await getVault(options.vault);
|
|
181
|
-
let content = options.content || '';
|
|
182
|
-
|
|
183
|
-
if (options.file) {
|
|
184
|
-
// Validate file path is within current working directory to prevent path traversal
|
|
185
|
-
const cwd = process.cwd();
|
|
186
|
-
const resolvedFilePath = validatePathWithinBase(options.file, cwd);
|
|
187
|
-
content = fs.readFileSync(resolvedFilePath, 'utf-8');
|
|
188
|
-
} else if (options.stdin) {
|
|
189
|
-
content = fs.readFileSync(0, 'utf-8');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const doc = await vault.store({
|
|
193
|
-
category: options.category,
|
|
194
|
-
title: options.title,
|
|
195
|
-
content,
|
|
196
|
-
overwrite: options.overwrite
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
console.log(chalk.green(`✓ Stored: ${doc.id}`));
|
|
200
|
-
console.log(chalk.dim(` Path: ${doc.path}`));
|
|
201
|
-
|
|
202
|
-
if (options.index !== false) {
|
|
203
|
-
const collection = vault.getQmdCollection();
|
|
204
|
-
await runQmd(collection ? ['update', '-c', collection] : ['update']);
|
|
205
|
-
if (options.embed) {
|
|
206
|
-
await runQmd(collection ? ['embed', '-c', collection] : ['embed']);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
} catch (err) {
|
|
210
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
211
|
-
process.exit(1);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// === CAPTURE ===
|
|
216
|
-
program
|
|
217
|
-
.command('capture <note>')
|
|
218
|
-
.description('Quick-capture a note to inbox')
|
|
219
|
-
.option('-t, --title <title>', 'Note title')
|
|
220
|
-
.option('-v, --vault <path>', 'Vault path')
|
|
221
|
-
.option('--no-index', 'Skip qmd index update (auto-updates by default)')
|
|
222
|
-
.action(async (note, options) => {
|
|
223
|
-
try {
|
|
224
|
-
const vault = await getVault(options.vault);
|
|
225
|
-
const doc = await vault.capture(note, options.title);
|
|
226
|
-
console.log(chalk.green(`✓ Captured: ${doc.id}`));
|
|
227
|
-
|
|
228
|
-
if (options.index !== false) {
|
|
229
|
-
const collection = vault.getQmdCollection();
|
|
230
|
-
await runQmd(collection ? ['update', '-c', collection] : ['update']);
|
|
231
|
-
}
|
|
232
|
-
} catch (err) {
|
|
233
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
234
|
-
process.exit(1);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Core vault lifecycle and write command registrations.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { validatePathWithinBase } from './command-runtime.js';
|
|
6
|
+
|
|
7
|
+
export function registerCoreCommands(
|
|
8
|
+
program,
|
|
9
|
+
{ chalk, path, fs, createVault, getVault, runQmd }
|
|
10
|
+
) {
|
|
11
|
+
// === INIT ===
|
|
12
|
+
program
|
|
13
|
+
.command('init [path]')
|
|
14
|
+
.description('Initialize a new ClawVault vault')
|
|
15
|
+
.option('-n, --name <name>', 'Vault name (default: target directory name)')
|
|
16
|
+
.option('--qmd', 'Set up qmd semantic search collection')
|
|
17
|
+
.option('--qmd-collection <name>', 'qmd collection name (defaults to vault name)')
|
|
18
|
+
.option('--no-bases', 'Skip Obsidian Bases file generation')
|
|
19
|
+
.option('--no-tasks', 'Skip tasks/ and backlog/ directories')
|
|
20
|
+
.option('--no-graph', 'Skip initial graph build')
|
|
21
|
+
.option('--categories <list>', 'Comma-separated list of custom categories to create')
|
|
22
|
+
.option('--canvas', 'Generate a vault status canvas dashboard on init')
|
|
23
|
+
.option('--theme <style>', 'Graph color theme to apply (neural, minimal, none) (default: none)', 'none')
|
|
24
|
+
.option('--minimal', 'Create minimal vault (memory categories only, no tasks/bases/graph)')
|
|
25
|
+
.action(async (vaultPath, options) => {
|
|
26
|
+
const targetPath = vaultPath || '.';
|
|
27
|
+
const resolvedPath = path.resolve(targetPath);
|
|
28
|
+
console.log(chalk.cyan(`\n🐘 Initializing ClawVault at ${resolvedPath}...\n`));
|
|
29
|
+
|
|
30
|
+
// Check for existing vault
|
|
31
|
+
const existingConfig = path.join(resolvedPath, '.clawvault.json');
|
|
32
|
+
if (fs.existsSync(existingConfig)) {
|
|
33
|
+
console.error(chalk.red(`Error: A ClawVault already exists at ${resolvedPath}`));
|
|
34
|
+
console.error(chalk.dim(' Use --force to reinitialize (not yet supported) or choose a different path.'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Resolve --minimal shorthand
|
|
40
|
+
const isMinimal = !!options.minimal;
|
|
41
|
+
const skipBases = isMinimal || options.bases === false;
|
|
42
|
+
const skipTasks = isMinimal || !!options.noTasks;
|
|
43
|
+
const skipGraph = isMinimal || !!options.noGraph;
|
|
44
|
+
|
|
45
|
+
// Resolve custom categories
|
|
46
|
+
const { DEFAULT_CATEGORIES } = await import('../dist/index.js');
|
|
47
|
+
let categories = [...DEFAULT_CATEGORIES];
|
|
48
|
+
if (options.categories) {
|
|
49
|
+
const customCats = options.categories.split(',').map(c => c.trim()).filter(Boolean);
|
|
50
|
+
categories = customCats;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const vault = await createVault(targetPath, {
|
|
54
|
+
name: options.name || path.basename(resolvedPath),
|
|
55
|
+
qmdCollection: options.qmdCollection,
|
|
56
|
+
categories
|
|
57
|
+
}, { skipBases, skipTasks, skipGraph });
|
|
58
|
+
|
|
59
|
+
const vaultCategories = vault.getCategories();
|
|
60
|
+
const memoryCategories = vaultCategories.filter(c => !['templates', 'tasks', 'backlog'].includes(c));
|
|
61
|
+
const workCategories = vaultCategories.filter(c => ['tasks', 'backlog'].includes(c));
|
|
62
|
+
|
|
63
|
+
console.log(chalk.green('✓ Vault created'));
|
|
64
|
+
console.log(chalk.dim(` Memory: ${memoryCategories.join(', ')}`));
|
|
65
|
+
if (workCategories.length > 0) {
|
|
66
|
+
console.log(chalk.dim(` Work: ${workCategories.join(', ')}`));
|
|
67
|
+
}
|
|
68
|
+
console.log(chalk.dim(` Ledger: ledger/raw, ledger/observations, ledger/reflections`));
|
|
69
|
+
if (skipBases) console.log(chalk.dim(' Bases: skipped'));
|
|
70
|
+
if (skipGraph) console.log(chalk.dim(' Graph: skipped'));
|
|
71
|
+
|
|
72
|
+
console.log(chalk.cyan('\nSetting up qmd collection...'));
|
|
73
|
+
try {
|
|
74
|
+
await runQmd([
|
|
75
|
+
'collection',
|
|
76
|
+
'add',
|
|
77
|
+
vault.getQmdRoot(),
|
|
78
|
+
'--name',
|
|
79
|
+
vault.getQmdCollection(),
|
|
80
|
+
'--mask',
|
|
81
|
+
'**/*.md'
|
|
82
|
+
]);
|
|
83
|
+
console.log(chalk.green('✓ qmd collection created'));
|
|
84
|
+
} catch {
|
|
85
|
+
console.log(chalk.yellow('⚠ qmd collection may already exist'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Apply theme if requested
|
|
89
|
+
if (options.theme && options.theme !== 'none') {
|
|
90
|
+
try {
|
|
91
|
+
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
92
|
+
await setupCommand({
|
|
93
|
+
graphColors: true,
|
|
94
|
+
bases: false,
|
|
95
|
+
canvas: false,
|
|
96
|
+
theme: options.theme,
|
|
97
|
+
vault: resolvedPath
|
|
98
|
+
});
|
|
99
|
+
} catch {
|
|
100
|
+
console.log(chalk.yellow(`⚠ Could not apply ${options.theme} theme`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Generate canvas if requested
|
|
105
|
+
if (options.canvas) {
|
|
106
|
+
try {
|
|
107
|
+
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
108
|
+
await setupCommand({
|
|
109
|
+
graphColors: false,
|
|
110
|
+
bases: false,
|
|
111
|
+
canvas: true,
|
|
112
|
+
theme: 'none',
|
|
113
|
+
vault: resolvedPath
|
|
114
|
+
});
|
|
115
|
+
} catch {
|
|
116
|
+
console.log(chalk.yellow(`⚠ Could not generate canvas`));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log(chalk.green('\n✅ ClawVault ready!\n'));
|
|
121
|
+
console.log(' ' + chalk.bold('Try these:'));
|
|
122
|
+
console.log(chalk.dim(' clawvault capture "my first thought" # quick capture'));
|
|
123
|
+
console.log(chalk.dim(' clawvault graph # see your knowledge graph'));
|
|
124
|
+
console.log(chalk.dim(' clawvault context "topic" # graph-aware context'));
|
|
125
|
+
console.log(chalk.dim(' clawvault checkpoint --working-on "task" # save progress'));
|
|
126
|
+
console.log();
|
|
127
|
+
console.log(chalk.dim(' Full docs: https://docs.clawvault.dev'));
|
|
128
|
+
console.log();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// === SETUP ===
|
|
136
|
+
program
|
|
137
|
+
.command('setup')
|
|
138
|
+
.description('Auto-discover and configure an existing ClawVault vault')
|
|
139
|
+
.option('--graph-colors', 'Set up graph color scheme for Obsidian')
|
|
140
|
+
.option('--no-graph-colors', 'Skip graph color configuration')
|
|
141
|
+
.option('--bases', 'Generate Obsidian Bases views for task management')
|
|
142
|
+
.option('--no-bases', 'Skip Bases file generation')
|
|
143
|
+
.option('--canvas', 'Generate vault status canvas dashboard')
|
|
144
|
+
.option('--no-canvas', 'Skip canvas generation')
|
|
145
|
+
.option('--theme <style>', 'Graph color theme (neural, minimal, none) (default: neural)', 'neural')
|
|
146
|
+
.option('--force', 'Overwrite existing configuration files')
|
|
147
|
+
.option('-v, --vault <path>', 'Vault path')
|
|
148
|
+
.action(async (options) => {
|
|
149
|
+
try {
|
|
150
|
+
const { setupCommand } = await import('../dist/commands/setup.js');
|
|
151
|
+
await setupCommand({
|
|
152
|
+
graphColors: options.graphColors,
|
|
153
|
+
bases: options.bases,
|
|
154
|
+
canvas: options.canvas,
|
|
155
|
+
theme: options.theme,
|
|
156
|
+
force: options.force,
|
|
157
|
+
vault: options.vault
|
|
158
|
+
});
|
|
159
|
+
} catch (err) {
|
|
160
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// === STORE ===
|
|
166
|
+
program
|
|
167
|
+
.command('store')
|
|
168
|
+
.description('Store a new memory document')
|
|
169
|
+
.requiredOption('-c, --category <category>', 'Category (preferences, decisions, patterns, people, projects, goals, transcripts, inbox)')
|
|
170
|
+
.requiredOption('-t, --title <title>', 'Document title')
|
|
171
|
+
.option('--content <content>', 'Content body')
|
|
172
|
+
.option('-f, --file <file>', 'Read content from file (validated against current working directory)')
|
|
173
|
+
.option('--stdin', 'Read content from stdin')
|
|
174
|
+
.option('--overwrite', 'Overwrite if exists')
|
|
175
|
+
.option('--no-index', 'Skip qmd index update (auto-updates by default)')
|
|
176
|
+
.option('--embed', 'Also update qmd embeddings for vector search')
|
|
177
|
+
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
178
|
+
.action(async (options) => {
|
|
179
|
+
try {
|
|
180
|
+
const vault = await getVault(options.vault);
|
|
181
|
+
let content = options.content || '';
|
|
182
|
+
|
|
183
|
+
if (options.file) {
|
|
184
|
+
// Validate file path is within current working directory to prevent path traversal
|
|
185
|
+
const cwd = process.cwd();
|
|
186
|
+
const resolvedFilePath = validatePathWithinBase(options.file, cwd);
|
|
187
|
+
content = fs.readFileSync(resolvedFilePath, 'utf-8');
|
|
188
|
+
} else if (options.stdin) {
|
|
189
|
+
content = fs.readFileSync(0, 'utf-8');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const doc = await vault.store({
|
|
193
|
+
category: options.category,
|
|
194
|
+
title: options.title,
|
|
195
|
+
content,
|
|
196
|
+
overwrite: options.overwrite
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
console.log(chalk.green(`✓ Stored: ${doc.id}`));
|
|
200
|
+
console.log(chalk.dim(` Path: ${doc.path}`));
|
|
201
|
+
|
|
202
|
+
if (options.index !== false) {
|
|
203
|
+
const collection = vault.getQmdCollection();
|
|
204
|
+
await runQmd(collection ? ['update', '-c', collection] : ['update']);
|
|
205
|
+
if (options.embed) {
|
|
206
|
+
await runQmd(collection ? ['embed', '-c', collection] : ['embed']);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// === CAPTURE ===
|
|
216
|
+
program
|
|
217
|
+
.command('capture <note>')
|
|
218
|
+
.description('Quick-capture a note to inbox')
|
|
219
|
+
.option('-t, --title <title>', 'Note title')
|
|
220
|
+
.option('-v, --vault <path>', 'Vault path')
|
|
221
|
+
.option('--no-index', 'Skip qmd index update (auto-updates by default)')
|
|
222
|
+
.action(async (note, options) => {
|
|
223
|
+
try {
|
|
224
|
+
const vault = await getVault(options.vault);
|
|
225
|
+
const doc = await vault.capture(note, options.title);
|
|
226
|
+
console.log(chalk.green(`✓ Captured: ${doc.id}`));
|
|
227
|
+
|
|
228
|
+
if (options.index !== false) {
|
|
229
|
+
const collection = vault.getQmdCollection();
|
|
230
|
+
await runQmd(collection ? ['update', '-c', collection] : ['update']);
|
|
231
|
+
}
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Kanban command registrations for ClawVault.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export function registerKanbanCommands(
|
|
6
|
-
program,
|
|
7
|
-
{ chalk, resolveVaultPath }
|
|
8
|
-
) {
|
|
9
|
-
const kanbanCmd = program
|
|
10
|
-
.command('kanban')
|
|
11
|
-
.description('Manage Obsidian Kanban sync for task frontmatter');
|
|
12
|
-
|
|
13
|
-
kanbanCmd
|
|
14
|
-
.command('sync')
|
|
15
|
-
.description('Generate and sync an Obsidian Kanban board from tasks')
|
|
16
|
-
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
17
|
-
.option('--output <path>', 'Board markdown path (default: Board.md)')
|
|
18
|
-
.option('--group-by <field>', 'Grouping field (status, priority, project, owner) (default: status)')
|
|
19
|
-
.option('--filter-project <project>', 'Only include tasks from a project')
|
|
20
|
-
.option('--filter-owner <owner>', 'Only include tasks for an owner')
|
|
21
|
-
.option('--include-done', 'Include done tasks (default: hidden)')
|
|
22
|
-
.action(async (options) => {
|
|
23
|
-
try {
|
|
24
|
-
const vaultPath = resolveVaultPath(options.vault);
|
|
25
|
-
const { kanbanCommand } = await import('../dist/commands/kanban.js');
|
|
26
|
-
await kanbanCommand(vaultPath, 'sync', {
|
|
27
|
-
output: options.output,
|
|
28
|
-
groupBy: options.groupBy,
|
|
29
|
-
filterProject: options.filterProject,
|
|
30
|
-
filterOwner: options.filterOwner,
|
|
31
|
-
includeDone: options.includeDone
|
|
32
|
-
});
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
kanbanCmd
|
|
40
|
-
.command('import')
|
|
41
|
-
.description('Import lane state from an Obsidian Kanban board into tasks')
|
|
42
|
-
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
43
|
-
.option('--output <path>', 'Board markdown path (default: Board.md)')
|
|
44
|
-
.action(async (options) => {
|
|
45
|
-
try {
|
|
46
|
-
const vaultPath = resolveVaultPath(options.vault);
|
|
47
|
-
const { kanbanCommand } = await import('../dist/commands/kanban.js');
|
|
48
|
-
await kanbanCommand(vaultPath, 'import', {
|
|
49
|
-
output: options.output
|
|
50
|
-
});
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Kanban command registrations for ClawVault.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function registerKanbanCommands(
|
|
6
|
+
program,
|
|
7
|
+
{ chalk, resolveVaultPath }
|
|
8
|
+
) {
|
|
9
|
+
const kanbanCmd = program
|
|
10
|
+
.command('kanban')
|
|
11
|
+
.description('Manage Obsidian Kanban sync for task frontmatter');
|
|
12
|
+
|
|
13
|
+
kanbanCmd
|
|
14
|
+
.command('sync')
|
|
15
|
+
.description('Generate and sync an Obsidian Kanban board from tasks')
|
|
16
|
+
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
17
|
+
.option('--output <path>', 'Board markdown path (default: Board.md)')
|
|
18
|
+
.option('--group-by <field>', 'Grouping field (status, priority, project, owner) (default: status)')
|
|
19
|
+
.option('--filter-project <project>', 'Only include tasks from a project')
|
|
20
|
+
.option('--filter-owner <owner>', 'Only include tasks for an owner')
|
|
21
|
+
.option('--include-done', 'Include done tasks (default: hidden)')
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
try {
|
|
24
|
+
const vaultPath = resolveVaultPath(options.vault);
|
|
25
|
+
const { kanbanCommand } = await import('../dist/commands/kanban.js');
|
|
26
|
+
await kanbanCommand(vaultPath, 'sync', {
|
|
27
|
+
output: options.output,
|
|
28
|
+
groupBy: options.groupBy,
|
|
29
|
+
filterProject: options.filterProject,
|
|
30
|
+
filterOwner: options.filterOwner,
|
|
31
|
+
includeDone: options.includeDone
|
|
32
|
+
});
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
kanbanCmd
|
|
40
|
+
.command('import')
|
|
41
|
+
.description('Import lane state from an Obsidian Kanban board into tasks')
|
|
42
|
+
.option('-v, --vault <path>', 'Vault path (default: find nearest)')
|
|
43
|
+
.option('--output <path>', 'Board markdown path (default: Board.md)')
|
|
44
|
+
.action(async (options) => {
|
|
45
|
+
try {
|
|
46
|
+
const vaultPath = resolveVaultPath(options.vault);
|
|
47
|
+
const { kanbanCommand } = await import('../dist/commands/kanban.js');
|
|
48
|
+
await kanbanCommand(vaultPath, 'import', {
|
|
49
|
+
output: options.output
|
|
50
|
+
});
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|