clawvault 2.4.6 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/bin/clawvault.js +5 -0
  2. package/bin/command-registration.test.js +1 -1
  3. package/bin/help-contract.test.js +1 -0
  4. package/bin/register-config-route-commands.test.js +8 -1
  5. package/bin/register-core-commands.js +3 -3
  6. package/bin/register-project-commands.js +209 -0
  7. package/bin/register-project-commands.test.js +201 -0
  8. package/bin/register-query-commands.js +40 -0
  9. package/bin/register-task-commands.js +2 -18
  10. package/bin/register-task-commands.test.js +3 -4
  11. package/bin/test-helpers/cli-command-fixtures.js +5 -0
  12. package/dist/{chunk-3PJIGGWV.js → chunk-2CDEETQN.js} +1 -0
  13. package/dist/{chunk-FD2ZA65C.js → chunk-2RK2AG32.js} +5 -5
  14. package/dist/chunk-5GZFTAL7.js +340 -0
  15. package/dist/{chunk-P2ZH6AN5.js → chunk-6RQPD7X6.js} +3 -4
  16. package/dist/{chunk-HNMFXFYP.js → chunk-7OHQFMJK.js} +2 -1
  17. package/dist/{chunk-FKQJB6XC.js → chunk-C3PF7WBA.js} +2 -2
  18. package/dist/{chunk-JXY6T5R7.js → chunk-FW465EEA.js} +1 -1
  19. package/dist/{chunk-BI6SGGZP.js → chunk-G3OQJ2NQ.js} +1 -1
  20. package/dist/chunk-GSD4ALSI.js +724 -0
  21. package/dist/{chunk-6QLRSPLZ.js → chunk-IOALNTAN.js} +268 -47
  22. package/dist/chunk-ITPEXLHA.js +528 -0
  23. package/dist/{chunk-LLN5SPGL.js → chunk-J5EMBUPK.js} +1 -1
  24. package/dist/chunk-K3CDT7IH.js +122 -0
  25. package/dist/{chunk-AHGUJG76.js → chunk-KCCHROBR.js} +13 -69
  26. package/dist/{chunk-JTO7NZLS.js → chunk-LMCC5OC7.js} +2 -2
  27. package/dist/{chunk-QALB2V3E.js → chunk-MQUJNOHK.js} +1 -1
  28. package/dist/{chunk-H6WQUUNK.js → chunk-TMZMN7OS.js} +334 -457
  29. package/dist/{chunk-HVTTYDCJ.js → chunk-VR5NE7PZ.js} +1 -1
  30. package/dist/{chunk-22WE3J4F.js → chunk-WIICLBNF.js} +35 -4
  31. package/dist/chunk-YCVDVI5B.js +273 -0
  32. package/dist/{chunk-NAMFB7ZA.js → chunk-Z2XBWN7A.js} +0 -2
  33. package/dist/commands/archive.js +3 -3
  34. package/dist/commands/backlog.js +1 -1
  35. package/dist/commands/blocked.js +1 -1
  36. package/dist/commands/canvas.d.ts +1 -14
  37. package/dist/commands/canvas.js +123 -1543
  38. package/dist/commands/context.js +5 -6
  39. package/dist/commands/doctor.js +2 -2
  40. package/dist/commands/inject.d.ts +2 -0
  41. package/dist/commands/inject.js +14 -0
  42. package/dist/commands/kanban.js +2 -2
  43. package/dist/commands/migrate-observations.js +2 -2
  44. package/dist/commands/observe.js +8 -6
  45. package/dist/commands/project.d.ts +85 -0
  46. package/dist/commands/project.js +411 -0
  47. package/dist/commands/rebuild.js +7 -5
  48. package/dist/commands/reflect.js +5 -4
  49. package/dist/commands/replay.js +10 -7
  50. package/dist/commands/setup.d.ts +1 -1
  51. package/dist/commands/setup.js +2 -2
  52. package/dist/commands/sleep.d.ts +1 -1
  53. package/dist/commands/sleep.js +11 -8
  54. package/dist/commands/status.js +2 -2
  55. package/dist/commands/task.d.ts +2 -2
  56. package/dist/commands/task.js +11 -301
  57. package/dist/commands/wake.d.ts +1 -1
  58. package/dist/commands/wake.js +4 -4
  59. package/dist/index.d.ts +75 -107
  60. package/dist/index.js +78 -36
  61. package/dist/inject-x65KXWPk.d.ts +137 -0
  62. package/dist/lib/project-utils.d.ts +97 -0
  63. package/dist/lib/project-utils.js +19 -0
  64. package/dist/lib/task-utils.d.ts +8 -3
  65. package/dist/lib/task-utils.js +1 -1
  66. package/dist/{types-DMU3SuAV.d.ts → types-jjuYN2Xn.d.ts} +1 -1
  67. package/package.json +2 -2
  68. package/dist/chunk-L3DJ36BZ.js +0 -40
  69. package/dist/chunk-UMMCYTJV.js +0 -105
@@ -0,0 +1,340 @@
1
+ import {
2
+ listTasks,
3
+ slugify
4
+ } from "./chunk-IOALNTAN.js";
5
+
6
+ // src/lib/project-utils.ts
7
+ import * as fs from "fs";
8
+ import * as path from "path";
9
+ import matter from "gray-matter";
10
+ function extractTitle(content) {
11
+ const match = content.match(/^#\s+(.+)$/m);
12
+ return match ? match[1].trim() : "";
13
+ }
14
+ function isDateSlug(slug) {
15
+ return /^\d{4}-\d{2}-\d{2}$/.test(slug);
16
+ }
17
+ function normalizeStringArray(value) {
18
+ return value.map((item) => item.trim()).filter(Boolean);
19
+ }
20
+ function getProjectsDir(vaultPath) {
21
+ return path.join(path.resolve(vaultPath), "projects");
22
+ }
23
+ function ensureProjectsDir(vaultPath) {
24
+ const projectsDir = getProjectsDir(vaultPath);
25
+ if (!fs.existsSync(projectsDir)) {
26
+ fs.mkdirSync(projectsDir, { recursive: true });
27
+ }
28
+ }
29
+ function getProjectPath(vaultPath, slug) {
30
+ return path.join(getProjectsDir(vaultPath), `${slug}.md`);
31
+ }
32
+ function parseProjectDateValue(filePath) {
33
+ const filename = path.basename(filePath, ".md");
34
+ if (/^\d{4}-\d{2}-\d{2}$/.test(filename)) {
35
+ const dateTs = Date.parse(`${filename}T00:00:00.000Z`);
36
+ if (!Number.isNaN(dateTs)) {
37
+ return dateTs;
38
+ }
39
+ }
40
+ return fs.statSync(filePath).mtime.getTime();
41
+ }
42
+ function parseSortableTimestamp(value) {
43
+ if (!value) return 0;
44
+ const timestamp = Date.parse(value);
45
+ return Number.isNaN(timestamp) ? 0 : timestamp;
46
+ }
47
+ function normalizeProjectStatus(value) {
48
+ if (value === "active" || value === "paused" || value === "completed" || value === "archived") {
49
+ return value;
50
+ }
51
+ return "active";
52
+ }
53
+ function normalizeProjectFrontmatter(frontmatter) {
54
+ const normalizedCreated = typeof frontmatter.created === "string" && frontmatter.created ? frontmatter.created : (/* @__PURE__ */ new Date(0)).toISOString();
55
+ const normalizedUpdated = typeof frontmatter.updated === "string" && frontmatter.updated ? frontmatter.updated : normalizedCreated;
56
+ const normalized = {
57
+ ...frontmatter,
58
+ type: "project",
59
+ status: normalizeProjectStatus(frontmatter.status),
60
+ created: normalizedCreated,
61
+ updated: normalizedUpdated
62
+ };
63
+ if (normalized.team) {
64
+ const team = normalizeStringArray(normalized.team);
65
+ if (team.length === 0) {
66
+ delete normalized.team;
67
+ } else {
68
+ normalized.team = team;
69
+ }
70
+ }
71
+ if (normalized.tags) {
72
+ const tags = normalizeStringArray(normalized.tags);
73
+ if (tags.length === 0) {
74
+ delete normalized.tags;
75
+ } else {
76
+ normalized.tags = tags;
77
+ }
78
+ }
79
+ return normalized;
80
+ }
81
+ function listProjects(vaultPath, filters) {
82
+ const projectsDir = getProjectsDir(vaultPath);
83
+ if (!fs.existsSync(projectsDir)) {
84
+ return [];
85
+ }
86
+ const projects = [];
87
+ const entries = fs.readdirSync(projectsDir, { withFileTypes: true });
88
+ for (const entry of entries) {
89
+ if (!entry.isFile() || !entry.name.endsWith(".md")) {
90
+ continue;
91
+ }
92
+ const slug = entry.name.replace(/\.md$/, "");
93
+ if (isDateSlug(slug)) {
94
+ continue;
95
+ }
96
+ const project = readProject(vaultPath, slug);
97
+ if (!project) continue;
98
+ if (filters) {
99
+ if (filters.status && project.frontmatter.status !== filters.status) continue;
100
+ if (filters.owner && project.frontmatter.owner !== filters.owner) continue;
101
+ if (filters.client && project.frontmatter.client !== filters.client) continue;
102
+ if (filters.tag) {
103
+ const tags = project.frontmatter.tags || [];
104
+ const hasTag = tags.some((tag) => tag.toLowerCase() === filters.tag?.toLowerCase());
105
+ if (!hasTag) continue;
106
+ }
107
+ }
108
+ projects.push(project);
109
+ }
110
+ return projects.sort((left, right) => {
111
+ const rightTime = parseSortableTimestamp(right.frontmatter.updated || right.frontmatter.created);
112
+ const leftTime = parseSortableTimestamp(left.frontmatter.updated || left.frontmatter.created);
113
+ return rightTime - leftTime;
114
+ });
115
+ }
116
+ function readProject(vaultPath, slug) {
117
+ if (!slug || isDateSlug(slug) || slug.includes(path.sep)) {
118
+ return null;
119
+ }
120
+ const projectPath = getProjectPath(vaultPath, slug);
121
+ if (!fs.existsSync(projectPath)) {
122
+ return null;
123
+ }
124
+ try {
125
+ const raw = fs.readFileSync(projectPath, "utf-8");
126
+ const { data, content } = matter(raw);
127
+ if (data.type !== "project") {
128
+ return null;
129
+ }
130
+ const frontmatter = normalizeProjectFrontmatter(data);
131
+ const title = extractTitle(content) || slug;
132
+ return {
133
+ slug,
134
+ title,
135
+ content,
136
+ frontmatter
137
+ };
138
+ } catch {
139
+ return null;
140
+ }
141
+ }
142
+ function createProject(vaultPath, title, options = {}) {
143
+ ensureProjectsDir(vaultPath);
144
+ const slug = slugify(title);
145
+ const projectPath = getProjectPath(vaultPath, slug);
146
+ if (fs.existsSync(projectPath)) {
147
+ throw new Error(`Project already exists: ${slug}`);
148
+ }
149
+ const now = (/* @__PURE__ */ new Date()).toISOString();
150
+ const frontmatter = {
151
+ type: "project",
152
+ status: options.status ?? "active",
153
+ created: now,
154
+ updated: now
155
+ };
156
+ if (options.owner) frontmatter.owner = options.owner;
157
+ if (options.team && options.team.length > 0) {
158
+ const team = normalizeStringArray(options.team);
159
+ if (team.length > 0) frontmatter.team = team;
160
+ }
161
+ if (options.client) frontmatter.client = options.client;
162
+ if (options.tags && options.tags.length > 0) {
163
+ const tags = normalizeStringArray(options.tags);
164
+ if (tags.length > 0) frontmatter.tags = tags;
165
+ }
166
+ if (options.description) frontmatter.description = options.description;
167
+ if (options.started) frontmatter.started = options.started;
168
+ if (options.deadline) frontmatter.deadline = options.deadline;
169
+ if (options.repo) frontmatter.repo = options.repo;
170
+ if (options.url) frontmatter.url = options.url;
171
+ if (options.completed) frontmatter.completed = options.completed;
172
+ if (options.reason) frontmatter.reason = options.reason;
173
+ let content = `# ${title}
174
+ `;
175
+ const wikiLinks = /* @__PURE__ */ new Set();
176
+ if (options.owner) wikiLinks.add(options.owner);
177
+ if (options.client) wikiLinks.add(options.client);
178
+ for (const member of options.team || []) {
179
+ const trimmed = member.trim();
180
+ if (trimmed) wikiLinks.add(trimmed);
181
+ }
182
+ if (wikiLinks.size > 0) {
183
+ content += `
184
+ ${Array.from(wikiLinks).map((link) => `[[${link}]]`).join(" | ")}
185
+ `;
186
+ }
187
+ if (options.content) {
188
+ content += `
189
+ ${options.content}
190
+ `;
191
+ }
192
+ const fileContent = matter.stringify(content, frontmatter);
193
+ fs.writeFileSync(projectPath, fileContent);
194
+ return {
195
+ slug,
196
+ title,
197
+ content,
198
+ frontmatter
199
+ };
200
+ }
201
+ function updateProject(vaultPath, slug, updates) {
202
+ const project = readProject(vaultPath, slug);
203
+ if (!project) {
204
+ throw new Error(`Project not found: ${slug}`);
205
+ }
206
+ const now = (/* @__PURE__ */ new Date()).toISOString();
207
+ const nextFrontmatter = {
208
+ ...project.frontmatter,
209
+ type: "project",
210
+ updated: now
211
+ };
212
+ if (updates.status !== void 0) {
213
+ nextFrontmatter.status = updates.status;
214
+ if (updates.status === "completed" && !updates.completed && !nextFrontmatter.completed) {
215
+ nextFrontmatter.completed = now;
216
+ }
217
+ }
218
+ if (updates.owner !== void 0) {
219
+ if (updates.owner === null || updates.owner.trim() === "") {
220
+ delete nextFrontmatter.owner;
221
+ } else {
222
+ nextFrontmatter.owner = updates.owner;
223
+ }
224
+ }
225
+ if (updates.team !== void 0) {
226
+ if (updates.team === null) {
227
+ delete nextFrontmatter.team;
228
+ } else {
229
+ const team = normalizeStringArray(updates.team);
230
+ if (team.length === 0) {
231
+ delete nextFrontmatter.team;
232
+ } else {
233
+ nextFrontmatter.team = team;
234
+ }
235
+ }
236
+ }
237
+ if (updates.client !== void 0) {
238
+ if (updates.client === null || updates.client.trim() === "") {
239
+ delete nextFrontmatter.client;
240
+ } else {
241
+ nextFrontmatter.client = updates.client;
242
+ }
243
+ }
244
+ if (updates.tags !== void 0) {
245
+ if (updates.tags === null) {
246
+ delete nextFrontmatter.tags;
247
+ } else {
248
+ const tags = normalizeStringArray(updates.tags);
249
+ if (tags.length === 0) {
250
+ delete nextFrontmatter.tags;
251
+ } else {
252
+ nextFrontmatter.tags = tags;
253
+ }
254
+ }
255
+ }
256
+ if (updates.description !== void 0) {
257
+ if (updates.description === null || updates.description.trim() === "") {
258
+ delete nextFrontmatter.description;
259
+ } else {
260
+ nextFrontmatter.description = updates.description;
261
+ }
262
+ }
263
+ if (updates.started !== void 0) {
264
+ if (updates.started === null || updates.started.trim() === "") {
265
+ delete nextFrontmatter.started;
266
+ } else {
267
+ nextFrontmatter.started = updates.started;
268
+ }
269
+ }
270
+ if (updates.deadline !== void 0) {
271
+ if (updates.deadline === null || updates.deadline.trim() === "") {
272
+ delete nextFrontmatter.deadline;
273
+ } else {
274
+ nextFrontmatter.deadline = updates.deadline;
275
+ }
276
+ }
277
+ if (updates.repo !== void 0) {
278
+ if (updates.repo === null || updates.repo.trim() === "") {
279
+ delete nextFrontmatter.repo;
280
+ } else {
281
+ nextFrontmatter.repo = updates.repo;
282
+ }
283
+ }
284
+ if (updates.url !== void 0) {
285
+ if (updates.url === null || updates.url.trim() === "") {
286
+ delete nextFrontmatter.url;
287
+ } else {
288
+ nextFrontmatter.url = updates.url;
289
+ }
290
+ }
291
+ if (updates.completed !== void 0) {
292
+ if (updates.completed === null || updates.completed.trim() === "") {
293
+ delete nextFrontmatter.completed;
294
+ } else {
295
+ nextFrontmatter.completed = updates.completed;
296
+ }
297
+ }
298
+ if (updates.reason !== void 0) {
299
+ if (updates.reason === null || updates.reason.trim() === "") {
300
+ delete nextFrontmatter.reason;
301
+ } else {
302
+ nextFrontmatter.reason = updates.reason;
303
+ }
304
+ }
305
+ const projectPath = getProjectPath(vaultPath, slug);
306
+ fs.writeFileSync(projectPath, matter.stringify(project.content, nextFrontmatter));
307
+ return {
308
+ ...project,
309
+ frontmatter: nextFrontmatter
310
+ };
311
+ }
312
+ function archiveProject(vaultPath, slug, reason) {
313
+ return updateProject(vaultPath, slug, {
314
+ status: "archived",
315
+ reason: reason ?? null,
316
+ completed: (/* @__PURE__ */ new Date()).toISOString()
317
+ });
318
+ }
319
+ function getProjectTasks(vaultPath, slug) {
320
+ return listTasks(vaultPath, { project: slug });
321
+ }
322
+ function getProjectActivity(vaultPath, slug) {
323
+ const projectActivityDir = path.join(getProjectsDir(vaultPath), slug);
324
+ if (!fs.existsSync(projectActivityDir) || !fs.statSync(projectActivityDir).isDirectory()) {
325
+ return [];
326
+ }
327
+ const entries = fs.readdirSync(projectActivityDir, { withFileTypes: true });
328
+ const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => path.join(projectActivityDir, entry.name));
329
+ return files.sort((left, right) => parseProjectDateValue(right) - parseProjectDateValue(left));
330
+ }
331
+
332
+ export {
333
+ listProjects,
334
+ readProject,
335
+ createProject,
336
+ updateProject,
337
+ archiveProject,
338
+ getProjectTasks,
339
+ getProjectActivity
340
+ };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-6B3JWM7J.js";
4
4
  import {
5
5
  DEFAULT_CATEGORIES
6
- } from "./chunk-3PJIGGWV.js";
6
+ } from "./chunk-2CDEETQN.js";
7
7
 
8
8
  // src/commands/setup.ts
9
9
  import * as fs from "fs";
@@ -327,10 +327,9 @@ async function setupCommand(options = {}) {
327
327
  }
328
328
  }
329
329
  if (doCanvas) {
330
- const templateId = typeof options.canvas === "string" ? options.canvas : "default";
331
330
  try {
332
331
  const { canvasCommand } = await import("./commands/canvas.js");
333
- await canvasCommand(target.vaultPath, { template: templateId });
332
+ await canvasCommand(target.vaultPath);
334
333
  } catch (err) {
335
334
  console.log(`\u26A0 Canvas generation failed: ${err instanceof Error ? err.message : String(err)}`);
336
335
  }
@@ -353,7 +352,7 @@ async function setupCommand(options = {}) {
353
352
  console.log("\nCustomize further:");
354
353
  console.log(" clawvault setup --theme neural # Neural neural graph colors");
355
354
  console.log(" clawvault setup --theme minimal # Subtle category colors");
356
- console.log(" clawvault setup --canvas brain # Generate brain architecture canvas");
355
+ console.log(" clawvault setup --canvas # Generate vault status canvas");
357
356
  console.log(" clawvault setup --no-bases --no-graph-colors # Structure only");
358
357
  console.log(" clawvault setup --force # Overwrite existing configs");
359
358
  }
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  DEFAULT_CATEGORIES,
12
12
  TYPE_TO_CATEGORY
13
- } from "./chunk-3PJIGGWV.js";
13
+ } from "./chunk-2CDEETQN.js";
14
14
  import {
15
15
  buildOrUpdateMemoryGraphIndex
16
16
  } from "./chunk-ZZA73MFY.js";
@@ -851,6 +851,7 @@ clawvault wake # restore context on startup
851
851
  facts: "Raw information, data points, things that are true",
852
852
  feelings: "Emotional states, reactions, energy levels",
853
853
  decisions: "Choices made with context and reasoning",
854
+ rules: "Injectable operational constraints, guardrails, and runbooks",
854
855
  lessons: "What I learned, insights, patterns observed",
855
856
  commitments: "Promises, goals, obligations to fulfill",
856
857
  preferences: "Likes, dislikes, how I want things",
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runReflection
3
- } from "./chunk-AHGUJG76.js";
3
+ } from "./chunk-KCCHROBR.js";
4
4
  import {
5
5
  Observer
6
- } from "./chunk-H6WQUUNK.js";
6
+ } from "./chunk-TMZMN7OS.js";
7
7
  import {
8
8
  resolveVaultPath
9
9
  } from "./chunk-MXSSG3QU.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-FHFUXL6G.js";
9
9
  import {
10
10
  listObservationFiles
11
- } from "./chunk-NAMFB7ZA.js";
11
+ } from "./chunk-Z2XBWN7A.js";
12
12
 
13
13
  // src/commands/migrate-observations.ts
14
14
  import * as fs from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runReflection
3
- } from "./chunk-AHGUJG76.js";
3
+ } from "./chunk-KCCHROBR.js";
4
4
  import {
5
5
  resolveVaultPath
6
6
  } from "./chunk-MXSSG3QU.js";