clawvault 2.2.0 → 2.3.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/bin/clawvault.js +6 -0
- package/bin/register-core-commands.js +14 -4
- package/bin/register-task-commands.js +257 -0
- package/dist/{chunk-DHBDH4DN.js → chunk-FDJIZKCW.js} +8 -1
- package/dist/chunk-MDIH26GC.js +183 -0
- package/dist/chunk-NGVAEFT2.js +352 -0
- package/dist/{chunk-IFGDPIFI.js → chunk-OTQW3OMC.js} +89 -10
- package/dist/{chunk-6RIHODNR.js → chunk-SOTWYGH7.js} +6 -6
- package/dist/{chunk-KNDVXXKC.js → chunk-W463YRED.js} +1 -1
- package/dist/commands/archive.js +1 -1
- package/dist/commands/backlog.d.ts +53 -0
- package/dist/commands/backlog.js +119 -0
- package/dist/commands/blocked.d.ts +25 -0
- package/dist/commands/blocked.js +43 -0
- package/dist/commands/canvas.d.ts +20 -0
- package/dist/commands/canvas.js +309 -0
- package/dist/commands/context.js +4 -4
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/graph.js +2 -2
- package/dist/commands/link.js +3 -3
- package/dist/commands/migrate-observations.js +2 -2
- package/dist/commands/observe.js +3 -3
- package/dist/commands/rebuild.js +2 -2
- package/dist/commands/recover.js +2 -2
- package/dist/commands/reflect.js +1 -1
- package/dist/commands/replay.js +3 -3
- package/dist/commands/setup.js +2 -2
- package/dist/commands/sleep.js +7 -7
- package/dist/commands/status.js +3 -3
- package/dist/commands/task.d.ts +71 -0
- package/dist/commands/task.js +189 -0
- package/dist/commands/wake.js +7 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +41 -41
- package/dist/lib/canvas-layout.d.ts +115 -0
- package/dist/lib/canvas-layout.js +34 -0
- package/dist/lib/task-utils.d.ts +159 -0
- package/dist/lib/task-utils.js +46 -0
- package/package.json +2 -2
- package/dist/{chunk-WZI3OAE5.js → chunk-5WR6RRPX.js} +3 -3
- package/dist/{chunk-L6NB43WV.js → chunk-6BBTI7NV.js} +3 -3
- package/dist/{chunk-73P7XCQM.js → chunk-DPS7NYIU.js} +3 -3
- package/dist/{chunk-MILVYUPK.js → chunk-IWYZAXKJ.js} +3 -3
- package/dist/{chunk-H7JW4L7H.js → chunk-OZ7RIXTO.js} +3 -3
- package/dist/{chunk-LB6P4CD5.js → chunk-PTSEIWXZ.js} +6 -6
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// src/lib/task-utils.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import matter from "gray-matter";
|
|
5
|
+
function slugify(text) {
|
|
6
|
+
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").trim();
|
|
7
|
+
}
|
|
8
|
+
function getTasksDir(vaultPath) {
|
|
9
|
+
return path.join(path.resolve(vaultPath), "tasks");
|
|
10
|
+
}
|
|
11
|
+
function getBacklogDir(vaultPath) {
|
|
12
|
+
return path.join(path.resolve(vaultPath), "backlog");
|
|
13
|
+
}
|
|
14
|
+
function ensureTasksDir(vaultPath) {
|
|
15
|
+
const tasksDir = getTasksDir(vaultPath);
|
|
16
|
+
if (!fs.existsSync(tasksDir)) {
|
|
17
|
+
fs.mkdirSync(tasksDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function ensureBacklogDir(vaultPath) {
|
|
21
|
+
const backlogDir = getBacklogDir(vaultPath);
|
|
22
|
+
if (!fs.existsSync(backlogDir)) {
|
|
23
|
+
fs.mkdirSync(backlogDir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getTaskPath(vaultPath, slug) {
|
|
27
|
+
return path.join(getTasksDir(vaultPath), `${slug}.md`);
|
|
28
|
+
}
|
|
29
|
+
function getBacklogPath(vaultPath, slug) {
|
|
30
|
+
return path.join(getBacklogDir(vaultPath), `${slug}.md`);
|
|
31
|
+
}
|
|
32
|
+
function extractTitle(content) {
|
|
33
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
34
|
+
return match ? match[1].trim() : "";
|
|
35
|
+
}
|
|
36
|
+
function readTask(vaultPath, slug) {
|
|
37
|
+
const taskPath = getTaskPath(vaultPath, slug);
|
|
38
|
+
if (!fs.existsSync(taskPath)) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const raw = fs.readFileSync(taskPath, "utf-8");
|
|
43
|
+
const { data, content } = matter(raw);
|
|
44
|
+
const title = extractTitle(content) || slug;
|
|
45
|
+
return {
|
|
46
|
+
slug,
|
|
47
|
+
title,
|
|
48
|
+
content,
|
|
49
|
+
frontmatter: data,
|
|
50
|
+
path: taskPath
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function readBacklogItem(vaultPath, slug) {
|
|
57
|
+
const backlogPath = getBacklogPath(vaultPath, slug);
|
|
58
|
+
if (!fs.existsSync(backlogPath)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const raw = fs.readFileSync(backlogPath, "utf-8");
|
|
63
|
+
const { data, content } = matter(raw);
|
|
64
|
+
const title = extractTitle(content) || slug;
|
|
65
|
+
return {
|
|
66
|
+
slug,
|
|
67
|
+
title,
|
|
68
|
+
content,
|
|
69
|
+
frontmatter: data,
|
|
70
|
+
path: backlogPath
|
|
71
|
+
};
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function listTasks(vaultPath, filters) {
|
|
77
|
+
const tasksDir = getTasksDir(vaultPath);
|
|
78
|
+
if (!fs.existsSync(tasksDir)) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
const tasks = [];
|
|
82
|
+
const entries = fs.readdirSync(tasksDir, { withFileTypes: true });
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const slug = entry.name.replace(/\.md$/, "");
|
|
88
|
+
const task = readTask(vaultPath, slug);
|
|
89
|
+
if (!task) continue;
|
|
90
|
+
if (filters) {
|
|
91
|
+
if (filters.status && task.frontmatter.status !== filters.status) continue;
|
|
92
|
+
if (filters.owner && task.frontmatter.owner !== filters.owner) continue;
|
|
93
|
+
if (filters.project && task.frontmatter.project !== filters.project) continue;
|
|
94
|
+
if (filters.priority && task.frontmatter.priority !== filters.priority) continue;
|
|
95
|
+
}
|
|
96
|
+
tasks.push(task);
|
|
97
|
+
}
|
|
98
|
+
const priorityOrder = {
|
|
99
|
+
critical: 0,
|
|
100
|
+
high: 1,
|
|
101
|
+
medium: 2,
|
|
102
|
+
low: 3
|
|
103
|
+
};
|
|
104
|
+
return tasks.sort((a, b) => {
|
|
105
|
+
const aPriority = priorityOrder[a.frontmatter.priority || "low"];
|
|
106
|
+
const bPriority = priorityOrder[b.frontmatter.priority || "low"];
|
|
107
|
+
if (aPriority !== bPriority) {
|
|
108
|
+
return aPriority - bPriority;
|
|
109
|
+
}
|
|
110
|
+
return new Date(b.frontmatter.created).getTime() - new Date(a.frontmatter.created).getTime();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function listBacklogItems(vaultPath, filters) {
|
|
114
|
+
const backlogDir = getBacklogDir(vaultPath);
|
|
115
|
+
if (!fs.existsSync(backlogDir)) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const items = [];
|
|
119
|
+
const entries = fs.readdirSync(backlogDir, { withFileTypes: true });
|
|
120
|
+
for (const entry of entries) {
|
|
121
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const slug = entry.name.replace(/\.md$/, "");
|
|
125
|
+
const item = readBacklogItem(vaultPath, slug);
|
|
126
|
+
if (!item) continue;
|
|
127
|
+
if (filters) {
|
|
128
|
+
if (filters.project && item.frontmatter.project !== filters.project) continue;
|
|
129
|
+
if (filters.source && item.frontmatter.source !== filters.source) continue;
|
|
130
|
+
}
|
|
131
|
+
items.push(item);
|
|
132
|
+
}
|
|
133
|
+
return items.sort((a, b) => {
|
|
134
|
+
return new Date(b.frontmatter.created).getTime() - new Date(a.frontmatter.created).getTime();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function createTask(vaultPath, title, options = {}) {
|
|
138
|
+
ensureTasksDir(vaultPath);
|
|
139
|
+
const slug = slugify(title);
|
|
140
|
+
const taskPath = getTaskPath(vaultPath, slug);
|
|
141
|
+
if (fs.existsSync(taskPath)) {
|
|
142
|
+
throw new Error(`Task already exists: ${slug}`);
|
|
143
|
+
}
|
|
144
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
145
|
+
const frontmatter = {
|
|
146
|
+
status: "open",
|
|
147
|
+
created: now,
|
|
148
|
+
updated: now
|
|
149
|
+
};
|
|
150
|
+
if (options.owner) frontmatter.owner = options.owner;
|
|
151
|
+
if (options.project) frontmatter.project = options.project;
|
|
152
|
+
if (options.priority) frontmatter.priority = options.priority;
|
|
153
|
+
if (options.due) frontmatter.due = options.due;
|
|
154
|
+
if (options.tags && options.tags.length > 0) frontmatter.tags = options.tags;
|
|
155
|
+
let content = `# ${title}
|
|
156
|
+
`;
|
|
157
|
+
const links = [];
|
|
158
|
+
if (options.owner) links.push(`[[${options.owner}]]`);
|
|
159
|
+
if (options.project) links.push(`[[${options.project}]]`);
|
|
160
|
+
if (links.length > 0) {
|
|
161
|
+
content += `
|
|
162
|
+
${links.join(" | ")}
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
if (options.content) {
|
|
166
|
+
content += `
|
|
167
|
+
${options.content}
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
const fileContent = matter.stringify(content, frontmatter);
|
|
171
|
+
fs.writeFileSync(taskPath, fileContent);
|
|
172
|
+
return {
|
|
173
|
+
slug,
|
|
174
|
+
title,
|
|
175
|
+
content,
|
|
176
|
+
frontmatter,
|
|
177
|
+
path: taskPath
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function updateTask(vaultPath, slug, updates) {
|
|
181
|
+
const task = readTask(vaultPath, slug);
|
|
182
|
+
if (!task) {
|
|
183
|
+
throw new Error(`Task not found: ${slug}`);
|
|
184
|
+
}
|
|
185
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
186
|
+
const newFrontmatter = {
|
|
187
|
+
...task.frontmatter,
|
|
188
|
+
updated: now
|
|
189
|
+
};
|
|
190
|
+
if (updates.status !== void 0) newFrontmatter.status = updates.status;
|
|
191
|
+
if (updates.owner !== void 0) newFrontmatter.owner = updates.owner;
|
|
192
|
+
if (updates.project !== void 0) newFrontmatter.project = updates.project;
|
|
193
|
+
if (updates.priority !== void 0) newFrontmatter.priority = updates.priority;
|
|
194
|
+
if (updates.due !== void 0) newFrontmatter.due = updates.due;
|
|
195
|
+
if (updates.tags !== void 0) newFrontmatter.tags = updates.tags;
|
|
196
|
+
if (updates.blocked_by !== void 0) {
|
|
197
|
+
newFrontmatter.blocked_by = updates.blocked_by;
|
|
198
|
+
} else if (updates.status && updates.status !== "blocked") {
|
|
199
|
+
delete newFrontmatter.blocked_by;
|
|
200
|
+
}
|
|
201
|
+
const fileContent = matter.stringify(task.content, newFrontmatter);
|
|
202
|
+
fs.writeFileSync(task.path, fileContent);
|
|
203
|
+
return {
|
|
204
|
+
...task,
|
|
205
|
+
frontmatter: newFrontmatter
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function completeTask(vaultPath, slug) {
|
|
209
|
+
const task = readTask(vaultPath, slug);
|
|
210
|
+
if (!task) {
|
|
211
|
+
throw new Error(`Task not found: ${slug}`);
|
|
212
|
+
}
|
|
213
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
214
|
+
const newFrontmatter = {
|
|
215
|
+
...task.frontmatter,
|
|
216
|
+
status: "done",
|
|
217
|
+
updated: now,
|
|
218
|
+
completed: now
|
|
219
|
+
};
|
|
220
|
+
delete newFrontmatter.blocked_by;
|
|
221
|
+
const fileContent = matter.stringify(task.content, newFrontmatter);
|
|
222
|
+
fs.writeFileSync(task.path, fileContent);
|
|
223
|
+
return {
|
|
224
|
+
...task,
|
|
225
|
+
frontmatter: newFrontmatter
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function createBacklogItem(vaultPath, title, options = {}) {
|
|
229
|
+
ensureBacklogDir(vaultPath);
|
|
230
|
+
const slug = slugify(title);
|
|
231
|
+
const backlogPath = getBacklogPath(vaultPath, slug);
|
|
232
|
+
if (fs.existsSync(backlogPath)) {
|
|
233
|
+
throw new Error(`Backlog item already exists: ${slug}`);
|
|
234
|
+
}
|
|
235
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
236
|
+
const frontmatter = {
|
|
237
|
+
created: now
|
|
238
|
+
};
|
|
239
|
+
if (options.source) frontmatter.source = options.source;
|
|
240
|
+
if (options.project) frontmatter.project = options.project;
|
|
241
|
+
if (options.tags && options.tags.length > 0) frontmatter.tags = options.tags;
|
|
242
|
+
let content = `# ${title}
|
|
243
|
+
`;
|
|
244
|
+
const links = [];
|
|
245
|
+
if (options.source) links.push(`[[${options.source}]]`);
|
|
246
|
+
if (options.project) links.push(`[[${options.project}]]`);
|
|
247
|
+
if (links.length > 0) {
|
|
248
|
+
content += `
|
|
249
|
+
${links.join(" | ")}
|
|
250
|
+
`;
|
|
251
|
+
}
|
|
252
|
+
if (options.content) {
|
|
253
|
+
content += `
|
|
254
|
+
${options.content}
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
const fileContent = matter.stringify(content, frontmatter);
|
|
258
|
+
fs.writeFileSync(backlogPath, fileContent);
|
|
259
|
+
return {
|
|
260
|
+
slug,
|
|
261
|
+
title,
|
|
262
|
+
content,
|
|
263
|
+
frontmatter,
|
|
264
|
+
path: backlogPath
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function promoteBacklogItem(vaultPath, slug, options = {}) {
|
|
268
|
+
const backlogItem = readBacklogItem(vaultPath, slug);
|
|
269
|
+
if (!backlogItem) {
|
|
270
|
+
throw new Error(`Backlog item not found: ${slug}`);
|
|
271
|
+
}
|
|
272
|
+
const task = createTask(vaultPath, backlogItem.title, {
|
|
273
|
+
owner: options.owner,
|
|
274
|
+
project: backlogItem.frontmatter.project,
|
|
275
|
+
priority: options.priority,
|
|
276
|
+
due: options.due,
|
|
277
|
+
content: backlogItem.content.replace(/^#\s+.+\n/, "").trim(),
|
|
278
|
+
// Remove title from content
|
|
279
|
+
tags: backlogItem.frontmatter.tags
|
|
280
|
+
});
|
|
281
|
+
fs.unlinkSync(backlogItem.path);
|
|
282
|
+
return task;
|
|
283
|
+
}
|
|
284
|
+
function getBlockedTasks(vaultPath, project) {
|
|
285
|
+
const filters = { status: "blocked" };
|
|
286
|
+
if (project) filters.project = project;
|
|
287
|
+
return listTasks(vaultPath, filters);
|
|
288
|
+
}
|
|
289
|
+
function getActiveTasks(vaultPath, filters) {
|
|
290
|
+
const allTasks = listTasks(vaultPath, filters);
|
|
291
|
+
return allTasks.filter((t) => t.frontmatter.status === "open" || t.frontmatter.status === "in-progress");
|
|
292
|
+
}
|
|
293
|
+
function getRecentlyCompletedTasks(vaultPath, limit = 10) {
|
|
294
|
+
const allTasks = listTasks(vaultPath, { status: "done" });
|
|
295
|
+
return allTasks.filter((t) => t.frontmatter.completed).sort((a, b) => {
|
|
296
|
+
const aCompleted = new Date(a.frontmatter.completed || 0).getTime();
|
|
297
|
+
const bCompleted = new Date(b.frontmatter.completed || 0).getTime();
|
|
298
|
+
return bCompleted - aCompleted;
|
|
299
|
+
}).slice(0, limit);
|
|
300
|
+
}
|
|
301
|
+
function getStatusIcon(status) {
|
|
302
|
+
switch (status) {
|
|
303
|
+
case "in-progress":
|
|
304
|
+
return "\u25CF";
|
|
305
|
+
case "blocked":
|
|
306
|
+
return "\u25A0";
|
|
307
|
+
case "open":
|
|
308
|
+
return "\u25CB";
|
|
309
|
+
case "done":
|
|
310
|
+
return "\u2713";
|
|
311
|
+
default:
|
|
312
|
+
return "\u25CB";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function getStatusDisplay(status) {
|
|
316
|
+
switch (status) {
|
|
317
|
+
case "in-progress":
|
|
318
|
+
return "active";
|
|
319
|
+
case "blocked":
|
|
320
|
+
return "blocked";
|
|
321
|
+
case "open":
|
|
322
|
+
return "open";
|
|
323
|
+
case "done":
|
|
324
|
+
return "done";
|
|
325
|
+
default:
|
|
326
|
+
return status;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export {
|
|
331
|
+
slugify,
|
|
332
|
+
getTasksDir,
|
|
333
|
+
getBacklogDir,
|
|
334
|
+
ensureTasksDir,
|
|
335
|
+
ensureBacklogDir,
|
|
336
|
+
getTaskPath,
|
|
337
|
+
getBacklogPath,
|
|
338
|
+
readTask,
|
|
339
|
+
readBacklogItem,
|
|
340
|
+
listTasks,
|
|
341
|
+
listBacklogItems,
|
|
342
|
+
createTask,
|
|
343
|
+
updateTask,
|
|
344
|
+
completeTask,
|
|
345
|
+
createBacklogItem,
|
|
346
|
+
promoteBacklogItem,
|
|
347
|
+
getBlockedTasks,
|
|
348
|
+
getActiveTasks,
|
|
349
|
+
getRecentlyCompletedTasks,
|
|
350
|
+
getStatusIcon,
|
|
351
|
+
getStatusDisplay
|
|
352
|
+
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
hasQmd,
|
|
9
9
|
qmdEmbed,
|
|
10
10
|
qmdUpdate
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-FDJIZKCW.js";
|
|
12
12
|
import {
|
|
13
13
|
buildOrUpdateMemoryGraphIndex
|
|
14
14
|
} from "./chunk-ZZA73MFY.js";
|
|
@@ -58,11 +58,19 @@ var ClawVault = class {
|
|
|
58
58
|
fs.mkdirSync(catPath, { recursive: true });
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
const ledgerDirs = ["ledger/raw", "ledger/observations", "ledger/reflections"];
|
|
62
|
+
for (const dir of ledgerDirs) {
|
|
63
|
+
const dirPath = path.join(vaultPath, dir);
|
|
64
|
+
if (!fs.existsSync(dirPath)) {
|
|
65
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
61
68
|
await this.createTemplates();
|
|
62
69
|
const readmePath = path.join(vaultPath, "README.md");
|
|
63
70
|
if (!fs.existsSync(readmePath)) {
|
|
64
71
|
fs.writeFileSync(readmePath, this.generateReadme());
|
|
65
72
|
}
|
|
73
|
+
await this.createWelcomeNote();
|
|
66
74
|
const configPath = path.join(vaultPath, CONFIG_FILE);
|
|
67
75
|
const meta = {
|
|
68
76
|
name: this.config.name,
|
|
@@ -628,6 +636,51 @@ var ClawVault = class {
|
|
|
628
636
|
}
|
|
629
637
|
}
|
|
630
638
|
}
|
|
639
|
+
async createWelcomeNote() {
|
|
640
|
+
const inboxPath = path.join(this.config.path, "inbox", "welcome.md");
|
|
641
|
+
if (fs.existsSync(inboxPath)) return;
|
|
642
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
643
|
+
const content = `---
|
|
644
|
+
title: "Welcome to ${this.config.name}"
|
|
645
|
+
date: ${now}
|
|
646
|
+
type: fact
|
|
647
|
+
tags: [welcome, getting-started]
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
# Welcome to ${this.config.name}
|
|
651
|
+
|
|
652
|
+
Your vault is ready. Here's what you can do:
|
|
653
|
+
|
|
654
|
+
## Quick Start
|
|
655
|
+
|
|
656
|
+
- **Capture a thought:** \`clawvault capture "your note here"\`
|
|
657
|
+
- **Store structured memory:** \`clawvault store --category decisions --title "My Choice" --content "..."\`
|
|
658
|
+
- **Search your vault:** \`clawvault search "query"\`
|
|
659
|
+
- **See your knowledge graph:** \`clawvault graph\`
|
|
660
|
+
- **Get context for a topic:** \`clawvault context "topic"\`
|
|
661
|
+
|
|
662
|
+
## Vault Structure
|
|
663
|
+
|
|
664
|
+
Your vault organizes memories by type \u2014 decisions, lessons, people, projects, and more.
|
|
665
|
+
Each category is a folder. Each memory is a markdown file with frontmatter.
|
|
666
|
+
|
|
667
|
+
## Observational Memory
|
|
668
|
+
|
|
669
|
+
When connected to an AI agent (like OpenClaw), your vault can automatically observe
|
|
670
|
+
conversations and extract important memories \u2014 decisions, lessons, commitments \u2014 without
|
|
671
|
+
manual effort.
|
|
672
|
+
|
|
673
|
+
## Wiki-Links
|
|
674
|
+
|
|
675
|
+
Use \`[[double brackets]]\` to link between notes. Your memory graph tracks these
|
|
676
|
+
connections, building a knowledge network that grows with you.
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
*Delete this file anytime. It's just here to say hello.*
|
|
681
|
+
`;
|
|
682
|
+
fs.writeFileSync(inboxPath, content);
|
|
683
|
+
}
|
|
631
684
|
async syncMemoryGraphIndex(options = {}) {
|
|
632
685
|
try {
|
|
633
686
|
await buildOrUpdateMemoryGraphIndex(this.config.path, options);
|
|
@@ -635,29 +688,51 @@ var ClawVault = class {
|
|
|
635
688
|
}
|
|
636
689
|
}
|
|
637
690
|
generateReadme() {
|
|
638
|
-
|
|
691
|
+
const coreCategories = this.config.categories.filter((c) => !["templates", "tasks", "backlog"].includes(c));
|
|
692
|
+
const workCategories = this.config.categories.filter((c) => ["tasks", "backlog"].includes(c));
|
|
693
|
+
return `# ${this.config.name}
|
|
639
694
|
|
|
640
695
|
An elephant never forgets.
|
|
641
696
|
|
|
642
697
|
## Structure
|
|
643
698
|
|
|
644
|
-
|
|
699
|
+
### Memory Categories
|
|
700
|
+
${coreCategories.map((c) => `- \`${c}/\` \u2014 ${this.getCategoryDescription(c)}`).join("\n")}
|
|
645
701
|
|
|
646
|
-
|
|
702
|
+
### Work Tracking
|
|
703
|
+
${workCategories.map((c) => `- \`${c}/\` \u2014 ${this.getCategoryDescription(c)}`).join("\n")}
|
|
704
|
+
|
|
705
|
+
### Observational Memory
|
|
706
|
+
- \`ledger/raw/\` \u2014 Raw session transcripts (source of truth)
|
|
707
|
+
- \`ledger/observations/\` \u2014 Compressed observations with importance scores
|
|
708
|
+
- \`ledger/reflections/\` \u2014 Weekly reflection summaries
|
|
709
|
+
|
|
710
|
+
## Quick Reference
|
|
647
711
|
|
|
648
712
|
\`\`\`bash
|
|
713
|
+
# Capture a thought
|
|
714
|
+
clawvault capture "important insight about X"
|
|
715
|
+
|
|
716
|
+
# Store structured memory
|
|
717
|
+
clawvault store --category decisions --title "Choice" --content "We chose X because..."
|
|
718
|
+
|
|
719
|
+
# Search
|
|
649
720
|
clawvault search "query"
|
|
650
|
-
|
|
721
|
+
clawvault vsearch "semantic query" # vector search
|
|
651
722
|
|
|
652
|
-
|
|
723
|
+
# Knowledge graph
|
|
724
|
+
clawvault graph # vault stats
|
|
725
|
+
clawvault context "topic" # graph-aware context retrieval
|
|
653
726
|
|
|
654
|
-
|
|
655
|
-
clawvault
|
|
727
|
+
# Session lifecycle
|
|
728
|
+
clawvault checkpoint --working-on "task"
|
|
729
|
+
clawvault sleep "what I did" --next "what's next"
|
|
730
|
+
clawvault wake # restore context on startup
|
|
656
731
|
\`\`\`
|
|
657
732
|
|
|
658
733
|
---
|
|
659
734
|
|
|
660
|
-
*Managed by [ClawVault](https://
|
|
735
|
+
*Managed by [ClawVault](https://clawvault.dev)*
|
|
661
736
|
`;
|
|
662
737
|
}
|
|
663
738
|
getCategoryDescription(category) {
|
|
@@ -677,7 +752,11 @@ clawvault store --category inbox --title "note" --content "..."
|
|
|
677
752
|
goals: "Long-term and short-term objectives",
|
|
678
753
|
patterns: "Recurring behaviors (\u2192 lessons)",
|
|
679
754
|
inbox: "Quick capture \u2192 process later",
|
|
680
|
-
templates: "Templates for each document type"
|
|
755
|
+
templates: "Templates for each document type",
|
|
756
|
+
agents: "Other agents \u2014 capabilities, trust levels, coordination notes",
|
|
757
|
+
research: "Deep dives, analysis, reference material",
|
|
758
|
+
tasks: "Active work items with status and context",
|
|
759
|
+
backlog: "Future work \u2014 ideas and tasks not yet started"
|
|
681
760
|
};
|
|
682
761
|
return descriptions[category] || category;
|
|
683
762
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ClawVault
|
|
3
|
+
} from "./chunk-OTQW3OMC.js";
|
|
1
4
|
import {
|
|
2
5
|
parseObservationMarkdown
|
|
3
6
|
} from "./chunk-K6XHCUFL.js";
|
|
4
|
-
import {
|
|
5
|
-
listObservationFiles
|
|
6
|
-
} from "./chunk-Z2XBWN7A.js";
|
|
7
|
-
import {
|
|
8
|
-
ClawVault
|
|
9
|
-
} from "./chunk-IFGDPIFI.js";
|
|
10
7
|
import {
|
|
11
8
|
getMemoryGraph
|
|
12
9
|
} from "./chunk-ZZA73MFY.js";
|
|
10
|
+
import {
|
|
11
|
+
listObservationFiles
|
|
12
|
+
} from "./chunk-Z2XBWN7A.js";
|
|
13
13
|
|
|
14
14
|
// src/commands/context.ts
|
|
15
15
|
import * as path from "path";
|
package/dist/commands/archive.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { TaskPriority, BacklogItem, Task } from '../lib/task-utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Backlog command for ClawVault
|
|
5
|
+
* Manages backlog add/list/promote operations
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface BacklogAddOptions {
|
|
9
|
+
source?: string;
|
|
10
|
+
project?: string;
|
|
11
|
+
content?: string;
|
|
12
|
+
tags?: string[];
|
|
13
|
+
}
|
|
14
|
+
interface BacklogListOptions {
|
|
15
|
+
project?: string;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface BacklogPromoteOptions {
|
|
19
|
+
owner?: string;
|
|
20
|
+
priority?: TaskPriority;
|
|
21
|
+
due?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Add a new backlog item
|
|
25
|
+
*/
|
|
26
|
+
declare function backlogAdd(vaultPath: string, title: string, options?: BacklogAddOptions): BacklogItem;
|
|
27
|
+
/**
|
|
28
|
+
* List backlog items with optional filters
|
|
29
|
+
*/
|
|
30
|
+
declare function backlogList(vaultPath: string, options?: BacklogListOptions): BacklogItem[];
|
|
31
|
+
/**
|
|
32
|
+
* Promote a backlog item to a task
|
|
33
|
+
*/
|
|
34
|
+
declare function backlogPromote(vaultPath: string, slug: string, options?: BacklogPromoteOptions): Task;
|
|
35
|
+
/**
|
|
36
|
+
* Format backlog list for terminal display
|
|
37
|
+
*/
|
|
38
|
+
declare function formatBacklogList(items: BacklogItem[]): string;
|
|
39
|
+
/**
|
|
40
|
+
* Format backlog item details for display
|
|
41
|
+
*/
|
|
42
|
+
declare function formatBacklogDetails(item: BacklogItem): string;
|
|
43
|
+
/**
|
|
44
|
+
* Backlog command handler for CLI
|
|
45
|
+
* Note: The CLI uses "clawvault backlog <title>" as shorthand for add
|
|
46
|
+
*/
|
|
47
|
+
declare function backlogCommand(vaultPath: string, action: 'add' | 'list' | 'promote', args: {
|
|
48
|
+
title?: string;
|
|
49
|
+
slug?: string;
|
|
50
|
+
options?: BacklogAddOptions & BacklogListOptions & BacklogPromoteOptions;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
|
|
53
|
+
export { type BacklogAddOptions, type BacklogListOptions, type BacklogPromoteOptions, backlogAdd, backlogCommand, backlogList, backlogPromote, formatBacklogDetails, formatBacklogList };
|