clawvault 2.1.2 → 2.2.1

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 (55) hide show
  1. package/bin/command-registration.test.js +6 -1
  2. package/bin/help-contract.test.js +2 -0
  3. package/bin/register-core-commands.js +14 -4
  4. package/bin/register-maintenance-commands.js +111 -0
  5. package/bin/register-query-commands.js +32 -1
  6. package/bin/register-session-lifecycle-commands.js +2 -0
  7. package/dist/{chunk-5MQB7B37.js → chunk-2HM7ZI4X.js} +268 -434
  8. package/dist/chunk-73P7XCQM.js +104 -0
  9. package/dist/{chunk-MIIXBNO3.js → chunk-FDJIZKCW.js} +12 -1
  10. package/dist/chunk-GJEGPO7U.js +49 -0
  11. package/dist/chunk-GQVYQCY5.js +396 -0
  12. package/dist/{chunk-TXO34J3O.js → chunk-H7JW4L7H.js} +1 -1
  13. package/dist/{chunk-TBVI4N53.js → chunk-I5X6J4FX.js} +120 -95
  14. package/dist/chunk-K6XHCUFL.js +123 -0
  15. package/dist/chunk-L6NB43WV.js +472 -0
  16. package/dist/{chunk-FEQ2CQ3Y.js → chunk-LB6P4CD5.js} +20 -7
  17. package/dist/chunk-MGDEINGP.js +99 -0
  18. package/dist/chunk-MQUJNOHK.js +58 -0
  19. package/dist/{chunk-QFBKWDYR.js → chunk-OTQW3OMC.js} +91 -12
  20. package/dist/chunk-P5EPF6MB.js +182 -0
  21. package/dist/chunk-VR5NE7PZ.js +45 -0
  22. package/dist/{chunk-PIJGYMQZ.js → chunk-W463YRED.js} +1 -1
  23. package/dist/chunk-WZI3OAE5.js +111 -0
  24. package/dist/chunk-Z2XBWN7A.js +247 -0
  25. package/dist/{chunk-O5V7SD5C.js → chunk-ZZA73MFY.js} +1 -1
  26. package/dist/commands/archive.d.ts +11 -0
  27. package/dist/commands/archive.js +11 -0
  28. package/dist/commands/context.d.ts +1 -1
  29. package/dist/commands/context.js +6 -4
  30. package/dist/commands/doctor.js +6 -6
  31. package/dist/commands/graph.js +2 -2
  32. package/dist/commands/link.js +1 -1
  33. package/dist/commands/migrate-observations.d.ts +19 -0
  34. package/dist/commands/migrate-observations.js +13 -0
  35. package/dist/commands/observe.js +5 -2
  36. package/dist/commands/rebuild.d.ts +11 -0
  37. package/dist/commands/rebuild.js +12 -0
  38. package/dist/commands/reflect.d.ts +11 -0
  39. package/dist/commands/reflect.js +13 -0
  40. package/dist/commands/replay.d.ts +16 -0
  41. package/dist/commands/replay.js +14 -0
  42. package/dist/commands/setup.js +2 -2
  43. package/dist/commands/sleep.d.ts +1 -0
  44. package/dist/commands/sleep.js +29 -6
  45. package/dist/commands/status.js +6 -6
  46. package/dist/commands/sync-bd.d.ts +10 -0
  47. package/dist/commands/sync-bd.js +9 -0
  48. package/dist/commands/wake.js +53 -35
  49. package/dist/{context-COo8oq1k.d.ts → context-BUGaWpyL.d.ts} +1 -0
  50. package/dist/index.d.ts +56 -20
  51. package/dist/index.js +67 -16
  52. package/hooks/clawvault/HOOK.md +3 -2
  53. package/hooks/clawvault/handler.js +51 -0
  54. package/hooks/clawvault/handler.test.js +20 -0
  55. package/package.json +2 -2
@@ -4,18 +4,23 @@ import {
4
4
  import {
5
5
  clearDirtyFlag
6
6
  } from "../chunk-MZZJLQNQ.js";
7
+ import {
8
+ parseObservationMarkdown
9
+ } from "../chunk-K6XHCUFL.js";
10
+ import {
11
+ listObservationFiles
12
+ } from "../chunk-Z2XBWN7A.js";
7
13
  import "../chunk-7ZRP733D.js";
8
14
  import {
9
15
  ClawVault
10
- } from "../chunk-QFBKWDYR.js";
11
- import "../chunk-MIIXBNO3.js";
12
- import "../chunk-O5V7SD5C.js";
16
+ } from "../chunk-OTQW3OMC.js";
17
+ import "../chunk-FDJIZKCW.js";
18
+ import "../chunk-ZZA73MFY.js";
13
19
 
14
20
  // src/commands/wake.ts
15
21
  import * as fs from "fs";
16
22
  import * as path from "path";
17
23
  var DEFAULT_HANDOFF_LIMIT = 3;
18
- var OBSERVATION_HIGHLIGHT_RE = /^(🔴|🟡)\s+(.+)$/u;
19
24
  var MAX_WAKE_RED_OBSERVATIONS = 20;
20
25
  var MAX_WAKE_YELLOW_OBSERVATIONS = 10;
21
26
  var MAX_WAKE_OUTPUT_LINES = 100;
@@ -39,40 +44,48 @@ function buildWakeSummary(recovery, recap) {
39
44
  }
40
45
  return workSummary || "No recent work summary found.";
41
46
  }
42
- function formatDateKey(date) {
43
- return date.toISOString().split("T")[0];
44
- }
45
47
  function readRecentObservationHighlights(vaultPath) {
46
48
  const now = /* @__PURE__ */ new Date();
49
+ const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
50
+ const fileByDate = new Map(
51
+ listObservationFiles(vaultPath, {
52
+ includeLegacy: true,
53
+ includeArchive: false,
54
+ dedupeByDate: true
55
+ }).map((entry) => [entry.date, entry.path])
56
+ );
47
57
  const highlights = [];
48
58
  for (let daysAgo = 0; daysAgo < 7; daysAgo++) {
49
- const date = new Date(now);
50
- date.setDate(now.getDate() - daysAgo);
51
- const dateKey = formatDateKey(date);
52
- const filePath = path.join(vaultPath, "observations", `${dateKey}.md`);
53
- if (!fs.existsSync(filePath)) continue;
59
+ const date = new Date(today);
60
+ date.setUTCDate(today.getUTCDate() - daysAgo);
61
+ const dateKey = date.toISOString().slice(0, 10);
62
+ const filePath = fileByDate.get(dateKey);
63
+ if (!filePath || !fs.existsSync(filePath)) continue;
54
64
  const content = fs.readFileSync(filePath, "utf-8");
55
- const dayRed = [];
56
- const dayYellow = [];
57
- for (const line of content.split(/\r?\n/)) {
58
- const match = line.trim().match(OBSERVATION_HIGHLIGHT_RE);
59
- if (!match?.[2]) continue;
65
+ const parsed = parseObservationMarkdown(content).filter((record) => record.importance >= 0.4);
66
+ const dayStructural = [];
67
+ const dayPotential = [];
68
+ for (const record of parsed) {
60
69
  const item = {
61
70
  date: dateKey,
62
- priority: match[1],
63
- text: match[2].trim()
71
+ type: record.type,
72
+ importance: record.importance,
73
+ text: record.content.trim()
64
74
  };
65
- if (item.priority === "\u{1F534}") dayRed.push(item);
66
- else dayYellow.push(item);
75
+ if (record.importance >= 0.8) {
76
+ dayStructural.push(item);
77
+ } else {
78
+ dayPotential.push(item);
79
+ }
67
80
  }
68
81
  if (daysAgo === 0) {
69
- highlights.push(...dayRed, ...dayYellow);
82
+ highlights.push(...dayStructural, ...dayPotential);
70
83
  } else if (daysAgo === 1) {
71
- highlights.push(...dayRed, ...dayYellow.slice(0, 5));
84
+ highlights.push(...dayStructural, ...dayPotential.slice(0, 5));
72
85
  } else if (daysAgo <= 3) {
73
- highlights.push(...dayRed);
86
+ highlights.push(...dayStructural);
74
87
  } else {
75
- highlights.push(...dayRed.slice(0, 3));
88
+ highlights.push(...dayStructural.slice(0, 3));
76
89
  }
77
90
  }
78
91
  return highlights;
@@ -88,16 +101,19 @@ function compareByRecency(left, right) {
88
101
  if (left.date !== right.date) {
89
102
  return right.date.localeCompare(left.date);
90
103
  }
104
+ if (left.importance !== right.importance) {
105
+ return right.importance - left.importance;
106
+ }
91
107
  return timeFromObservationText(right.text) - timeFromObservationText(left.text);
92
108
  }
93
109
  function formatRecentObservations(highlights) {
94
110
  if (highlights.length === 0) {
95
- return "_No critical or notable observations from today or yesterday._";
111
+ return "_No structural or potentially important observations from the recent window._";
96
112
  }
97
113
  const sorted = [...highlights].sort(compareByRecency);
98
- const red = sorted.filter((item) => item.priority === "\u{1F534}").slice(0, MAX_WAKE_RED_OBSERVATIONS);
99
- const yellow = sorted.filter((item) => item.priority === "\u{1F7E1}").slice(0, MAX_WAKE_YELLOW_OBSERVATIONS);
100
- const visible = [...red, ...yellow].sort(compareByRecency);
114
+ const structural = sorted.filter((item) => item.importance >= 0.8).slice(0, MAX_WAKE_RED_OBSERVATIONS);
115
+ const potential = sorted.filter((item) => item.importance >= 0.4 && item.importance < 0.8).slice(0, MAX_WAKE_YELLOW_OBSERVATIONS);
116
+ const visible = [...structural, ...potential].sort(compareByRecency);
101
117
  const omittedCount = Math.max(0, highlights.length - visible.length);
102
118
  const byDate = /* @__PURE__ */ new Map();
103
119
  for (const item of visible) {
@@ -116,7 +132,7 @@ function formatRecentObservations(highlights) {
116
132
  if (lines.length >= bodyLineBudget) {
117
133
  break;
118
134
  }
119
- lines.push(`- ${item.priority} ${item.text}`);
135
+ lines.push(`- [${item.type}|i=${item.importance.toFixed(2)}] ${item.text}`);
120
136
  }
121
137
  if (lines.length < bodyLineBudget) {
122
138
  lines.push("");
@@ -131,8 +147,8 @@ async function generateExecutiveSummary(recovery, recap, highlights) {
131
147
  if (process.env.CLAWVAULT_NO_LLM || process.env.VITEST) return null;
132
148
  const apiKey = process.env.GEMINI_API_KEY || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
133
149
  if (!apiKey) return null;
134
- const redItems = highlights.filter((h) => h.priority === "\u{1F534}").map((h) => h.text).slice(0, 10);
135
- const yellowItems = highlights.filter((h) => h.priority === "\u{1F7E1}").map((h) => h.text).slice(0, 5);
150
+ const structuralItems = highlights.filter((h) => h.importance >= 0.8).map((h) => h.text).slice(0, 10);
151
+ const potentialItems = highlights.filter((h) => h.importance >= 0.4 && h.importance < 0.8).map((h) => h.text).slice(0, 5);
136
152
  const projects = recap.activeProjects.slice(0, 8);
137
153
  const commitments = recap.pendingCommitments.slice(0, 5);
138
154
  const lastWork = recovery.checkpoint?.workingOn || recap.recentHandoffs[0]?.workingOn?.join(", ") || "";
@@ -149,8 +165,8 @@ async function generateExecutiveSummary(recovery, recap, highlights) {
149
165
  `Next steps: ${nextSteps || "(none)"}`,
150
166
  `Active projects (${projects.length}): ${projects.join(", ") || "(none)"}`,
151
167
  `Pending commitments: ${commitments.join(", ") || "(none)"}`,
152
- `Critical observations: ${redItems.join(" | ") || "(none)"}`,
153
- `Notable observations: ${yellowItems.join(" | ") || "(none)"}`,
168
+ `Structural observations: ${structuralItems.join(" | ") || "(none)"}`,
169
+ `Potential observations: ${potentialItems.join(" | ") || "(none)"}`,
154
170
  "",
155
171
  "Write the briefing now. Be concise."
156
172
  ].join("\n");
@@ -190,7 +206,9 @@ async function wake(options) {
190
206
  const highlights = readRecentObservationHighlights(vaultPath);
191
207
  const observations = formatRecentObservations(highlights);
192
208
  const execSummary = options.noSummary ? null : await generateExecutiveSummary(recovery, recap, highlights);
193
- const highlightSummaryItems = highlights.map((item) => `${item.priority} ${item.text}`);
209
+ const highlightSummaryItems = highlights.map(
210
+ (item) => `[${item.type}|i=${item.importance.toFixed(2)}] ${item.text}`
211
+ );
194
212
  const wakeSummary = formatSummaryItems(highlightSummaryItems);
195
213
  const baseSummary = buildWakeSummary(recovery, recap);
196
214
  const fullBaseSummary = wakeSummary ? `${baseSummary} | ${wakeSummary}` : baseSummary;
@@ -17,6 +17,7 @@ interface ContextOptions {
17
17
  includeObservations?: boolean;
18
18
  budget?: number;
19
19
  profile?: ContextProfileOption;
20
+ maxHops?: number;
20
21
  }
21
22
  interface ContextEntry {
22
23
  title: string;
package/dist/index.d.ts CHANGED
@@ -4,8 +4,14 @@ export { f as DEFAULT_CATEGORIES, g as DEFAULT_CONFIG, h as MEMORY_TYPES, T as T
4
4
  export { setupCommand } from './commands/setup.js';
5
5
  export { CompatCheck, CompatCommandOptions, CompatReport, CompatStatus, checkOpenClawCompatibility, compatCommand, compatibilityExitCode } from './commands/compat.js';
6
6
  export { GraphSummary, graphCommand, graphSummary } from './commands/graph.js';
7
- export { C as ContextEntry, a as ContextFormat, b as ContextOptions, c as ContextProfile, d as ContextProfileInput, e as ContextProfileOption, f as ContextResult, R as ResolvedContextProfile, g as buildContext, h as contextCommand, i as formatContextMarkdown, j as inferContextProfile, n as normalizeContextProfileInput, r as registerContextCommand, k as resolveContextProfile } from './context-COo8oq1k.js';
7
+ export { C as ContextEntry, a as ContextFormat, b as ContextOptions, c as ContextProfile, d as ContextProfileInput, e as ContextProfileOption, f as ContextResult, R as ResolvedContextProfile, g as buildContext, h as contextCommand, i as formatContextMarkdown, j as inferContextProfile, n as normalizeContextProfileInput, r as registerContextCommand, k as resolveContextProfile } from './context-BUGaWpyL.js';
8
8
  export { ObserveCommandOptions, observeCommand, registerObserveCommand } from './commands/observe.js';
9
+ export { ReflectCommandOptions, reflectCommand, registerReflectCommand } from './commands/reflect.js';
10
+ export { ArchiveCommandOptions, archiveCommand, registerArchiveCommand } from './commands/archive.js';
11
+ export { RebuildCommandOptions, rebuildCommand, registerRebuildCommand } from './commands/rebuild.js';
12
+ export { ReplayCommandOptions, registerReplayCommand, replayCommand } from './commands/replay.js';
13
+ export { MigrateObservationsOptions, MigrateObservationsResult, migrateObservations, migrateObservationsCommand, registerMigrateObservationsCommand } from './commands/migrate-observations.js';
14
+ export { SyncBdCommandOptions, registerSyncBdCommand, syncBdCommand } from './commands/sync-bd.js';
9
15
  export { SessionRecapFormat, SessionRecapOptions, SessionRecapResult, SessionTurn, buildSessionRecap, formatSessionRecapMarkdown, sessionRecapCommand } from './commands/session-recap.js';
10
16
  export { findNearestVaultPath, getVaultPath, resolveVaultPath } from './lib/config.js';
11
17
  export { TemplateVariables, buildTemplateVariables, renderTemplate } from './lib/template-engine.js';
@@ -138,6 +144,7 @@ declare class ClawVault {
138
144
  private slugify;
139
145
  private saveIndex;
140
146
  private createTemplates;
147
+ private createWelcomeNote;
141
148
  private syncMemoryGraphIndex;
142
149
  private generateReadme;
143
150
  private getCategoryDescription;
@@ -337,21 +344,28 @@ interface ObserverOptions {
337
344
  compressor?: ObserverCompressor;
338
345
  reflector?: ObserverReflector;
339
346
  now?: () => Date;
347
+ rawCapture?: boolean;
348
+ }
349
+ interface ObserverProcessOptions {
350
+ source?: string;
351
+ sessionKey?: string;
352
+ transcriptId?: string;
353
+ timestamp?: Date;
340
354
  }
341
355
  declare class Observer {
342
356
  private readonly vaultPath;
343
- private readonly observationsDir;
344
357
  private readonly tokenThreshold;
345
358
  private readonly reflectThreshold;
346
359
  private readonly compressor;
347
360
  private readonly reflector;
348
361
  private readonly now;
362
+ private readonly rawCapture;
349
363
  private readonly router;
350
364
  private pendingMessages;
351
365
  private observationsCache;
352
366
  private lastRoutingSummary;
353
367
  constructor(vaultPath: string, options?: ObserverOptions);
354
- processMessages(messages: string[]): Promise<void>;
368
+ processMessages(messages: string[], options?: ObserverProcessOptions): Promise<void>;
355
369
  /**
356
370
  * Force-flush pending messages regardless of threshold.
357
371
  * Call this on session end to capture everything.
@@ -362,17 +376,13 @@ declare class Observer {
362
376
  }>;
363
377
  getObservations(): string;
364
378
  private estimateTokens;
365
- private getObservationPath;
366
379
  private readTodayObservations;
380
+ private readObservationForDate;
367
381
  private readObservationFile;
368
382
  private writeObservationFile;
369
- private getObservationFiles;
370
- private readObservationCorpus;
371
383
  private deduplicateObservationMarkdown;
372
- private parseSections;
373
- private renderSections;
374
- private normalizeObservationContent;
375
- private reflectIfNeeded;
384
+ private persistRawMessages;
385
+ private sanitizeSource;
376
386
  }
377
387
 
378
388
  interface CompressorOptions {
@@ -401,18 +411,14 @@ declare class Compressor {
401
411
  * Also fixes trailing word fragments fused after closing brackets.
402
412
  */
403
413
  private sanitizeWikiLinks;
404
- /**
405
- * Post-process LLM output to enforce priority rules.
406
- * Lines matching critical rules get upgraded to 🔴, notable rules to 🟡.
407
- */
408
- private enforcePriorityRules;
414
+ private enforceImportanceRules;
415
+ private enforceImportanceForRecord;
409
416
  private fallbackCompression;
410
417
  private mergeObservations;
411
- private deduplicateObservationLines;
412
- private normalizeObservationContent;
413
- private parseSections;
418
+ private mergeRecord;
414
419
  private renderSections;
415
- private inferPriority;
420
+ private inferImportance;
421
+ private inferConfidence;
416
422
  private isCriticalContent;
417
423
  private isNotableContent;
418
424
  private normalizeText;
@@ -420,6 +426,7 @@ declare class Compressor {
420
426
  private extractTime;
421
427
  private formatDate;
422
428
  private formatTime;
429
+ private clamp01;
423
430
  }
424
431
 
425
432
  interface ReflectorOptions {
@@ -466,6 +473,35 @@ declare class SessionWatcher {
466
473
 
467
474
  declare function parseSessionFile(filePath: string): string[];
468
475
 
476
+ interface ArchiveObservationsOptions {
477
+ olderThanDays?: number;
478
+ dryRun?: boolean;
479
+ now?: () => Date;
480
+ }
481
+ interface ArchiveObservationsResult {
482
+ scanned: number;
483
+ archived: number;
484
+ skipped: number;
485
+ dryRun: boolean;
486
+ archivedDates: string[];
487
+ }
488
+ declare function archiveObservations(vaultPath: string, options?: ArchiveObservationsOptions): ArchiveObservationsResult;
489
+
490
+ interface ReflectOptions {
491
+ vaultPath: string;
492
+ days?: number;
493
+ dryRun?: boolean;
494
+ now?: () => Date;
495
+ }
496
+ interface ReflectResult {
497
+ processedWeeks: number;
498
+ writtenWeeks: number;
499
+ dryRun: boolean;
500
+ files: string[];
501
+ archive: ArchiveObservationsResult | null;
502
+ }
503
+ declare function runReflection(options: ReflectOptions): Promise<ReflectResult>;
504
+
469
505
  /**
470
506
  * ClawVault 🐘 — An Elephant Never Forgets
471
507
  *
@@ -495,4 +531,4 @@ declare function parseSessionFile(filePath: string): string[];
495
531
  declare const VERSION: string;
496
532
  declare function registerCommanderCommands(program: Command): Command;
497
533
 
498
- export { Category, ClawVault, Compressor, type CompressorOptions, Document, HandoffDocument, MEMORY_GRAPH_SCHEMA_VERSION, type MemoryGraph, type MemoryGraphEdge, type MemoryGraphEdgeType, type MemoryGraphIndex, type MemoryGraphNode, type MemoryGraphNodeType, type MemoryGraphStats, MemoryType, Observer, type ObserverCompressor, type ObserverOptions, type ObserverReflector, QMD_INSTALL_COMMAND, QMD_INSTALL_URL, QmdUnavailableError, Reflector, type ReflectorOptions, SearchEngine, SearchOptions, SearchResult, SessionRecap, SessionWatcher, type SessionWatcherOptions, StoreOptions, SyncOptions, SyncResult, VERSION, VaultConfig, buildOrUpdateMemoryGraphIndex, createVault, extractTags, extractWikiLinks, findVault, getMemoryGraph, hasQmd, loadMemoryGraphIndex, parseSessionFile, qmdEmbed, qmdUpdate, registerCommanderCommands };
534
+ export { type ArchiveObservationsOptions, type ArchiveObservationsResult, Category, ClawVault, Compressor, type CompressorOptions, Document, HandoffDocument, MEMORY_GRAPH_SCHEMA_VERSION, type MemoryGraph, type MemoryGraphEdge, type MemoryGraphEdgeType, type MemoryGraphIndex, type MemoryGraphNode, type MemoryGraphNodeType, type MemoryGraphStats, MemoryType, Observer, type ObserverCompressor, type ObserverOptions, type ObserverReflector, QMD_INSTALL_COMMAND, QMD_INSTALL_URL, QmdUnavailableError, type ReflectOptions, type ReflectResult, Reflector, type ReflectorOptions, SearchEngine, SearchOptions, SearchResult, SessionRecap, SessionWatcher, type SessionWatcherOptions, StoreOptions, SyncOptions, SyncResult, VERSION, VaultConfig, archiveObservations, buildOrUpdateMemoryGraphIndex, createVault, extractTags, extractWikiLinks, findVault, getMemoryGraph, hasQmd, loadMemoryGraphIndex, parseSessionFile, qmdEmbed, qmdUpdate, registerCommanderCommands, runReflection };
package/dist/index.js CHANGED
@@ -1,27 +1,60 @@
1
+ import {
2
+ buildSessionRecap,
3
+ formatSessionRecapMarkdown,
4
+ sessionRecapCommand
5
+ } from "./chunk-ZKGY7WTT.js";
6
+ import {
7
+ setupCommand
8
+ } from "./chunk-W463YRED.js";
9
+ import {
10
+ registerSyncBdCommand,
11
+ syncBdCommand
12
+ } from "./chunk-MGDEINGP.js";
1
13
  import {
2
14
  buildTemplateVariables,
3
15
  renderTemplate
4
16
  } from "./chunk-7766SIJP.js";
17
+ import {
18
+ migrateObservations,
19
+ migrateObservationsCommand,
20
+ registerMigrateObservationsCommand
21
+ } from "./chunk-WZI3OAE5.js";
5
22
  import {
6
23
  SessionWatcher,
7
24
  observeCommand,
8
25
  registerObserveCommand
9
- } from "./chunk-FEQ2CQ3Y.js";
26
+ } from "./chunk-LB6P4CD5.js";
10
27
  import {
11
- buildSessionRecap,
12
- formatSessionRecapMarkdown,
13
- sessionRecapCommand
14
- } from "./chunk-ZKGY7WTT.js";
28
+ parseSessionFile
29
+ } from "./chunk-P5EPF6MB.js";
30
+ import {
31
+ rebuildCommand,
32
+ registerRebuildCommand
33
+ } from "./chunk-73P7XCQM.js";
34
+ import {
35
+ reflectCommand,
36
+ registerReflectCommand
37
+ } from "./chunk-GJEGPO7U.js";
15
38
  import "./chunk-HRLWZGMA.js";
16
39
  import {
17
- setupCommand
18
- } from "./chunk-PIJGYMQZ.js";
40
+ registerReplayCommand,
41
+ replayCommand
42
+ } from "./chunk-L6NB43WV.js";
19
43
  import {
20
44
  Compressor,
21
45
  Observer,
22
- Reflector,
23
- parseSessionFile
24
- } from "./chunk-5MQB7B37.js";
46
+ Reflector
47
+ } from "./chunk-2HM7ZI4X.js";
48
+ import {
49
+ runReflection
50
+ } from "./chunk-GQVYQCY5.js";
51
+ import {
52
+ archiveCommand,
53
+ registerArchiveCommand
54
+ } from "./chunk-VR5NE7PZ.js";
55
+ import {
56
+ archiveObservations
57
+ } from "./chunk-MQUJNOHK.js";
25
58
  import {
26
59
  buildContext,
27
60
  contextCommand,
@@ -30,7 +63,9 @@ import {
30
63
  normalizeContextProfileInput,
31
64
  registerContextCommand,
32
65
  resolveContextProfile
33
- } from "./chunk-TBVI4N53.js";
66
+ } from "./chunk-I5X6J4FX.js";
67
+ import "./chunk-K6XHCUFL.js";
68
+ import "./chunk-Z2XBWN7A.js";
34
69
  import {
35
70
  checkOpenClawCompatibility,
36
71
  compatCommand,
@@ -40,7 +75,7 @@ import {
40
75
  ClawVault,
41
76
  createVault,
42
77
  findVault
43
- } from "./chunk-QFBKWDYR.js";
78
+ } from "./chunk-OTQW3OMC.js";
44
79
  import {
45
80
  DEFAULT_CATEGORIES,
46
81
  DEFAULT_CONFIG,
@@ -55,17 +90,17 @@ import {
55
90
  hasQmd,
56
91
  qmdEmbed,
57
92
  qmdUpdate
58
- } from "./chunk-MIIXBNO3.js";
93
+ } from "./chunk-FDJIZKCW.js";
59
94
  import {
60
95
  graphCommand,
61
96
  graphSummary
62
- } from "./chunk-TXO34J3O.js";
97
+ } from "./chunk-H7JW4L7H.js";
63
98
  import {
64
99
  MEMORY_GRAPH_SCHEMA_VERSION,
65
100
  buildOrUpdateMemoryGraphIndex,
66
101
  getMemoryGraph,
67
102
  loadMemoryGraphIndex
68
- } from "./chunk-O5V7SD5C.js";
103
+ } from "./chunk-ZZA73MFY.js";
69
104
  import {
70
105
  findNearestVaultPath,
71
106
  getVaultPath,
@@ -87,6 +122,7 @@ var VERSION = readPackageVersion();
87
122
  function registerCommanderCommands(program) {
88
123
  registerContextCommand(program);
89
124
  registerObserveCommand(program);
125
+ registerReflectCommand(program);
90
126
  return program;
91
127
  }
92
128
  export {
@@ -105,6 +141,8 @@ export {
105
141
  SessionWatcher,
106
142
  TYPE_TO_CATEGORY,
107
143
  VERSION,
144
+ archiveCommand,
145
+ archiveObservations,
108
146
  buildContext,
109
147
  buildOrUpdateMemoryGraphIndex,
110
148
  buildSessionRecap,
@@ -127,17 +165,30 @@ export {
127
165
  hasQmd,
128
166
  inferContextProfile,
129
167
  loadMemoryGraphIndex,
168
+ migrateObservations,
169
+ migrateObservationsCommand,
130
170
  normalizeContextProfileInput,
131
171
  observeCommand,
132
172
  parseSessionFile,
133
173
  qmdEmbed,
134
174
  qmdUpdate,
175
+ rebuildCommand,
176
+ reflectCommand,
177
+ registerArchiveCommand,
135
178
  registerCommanderCommands,
136
179
  registerContextCommand,
180
+ registerMigrateObservationsCommand,
137
181
  registerObserveCommand,
182
+ registerRebuildCommand,
183
+ registerReflectCommand,
184
+ registerReplayCommand,
185
+ registerSyncBdCommand,
138
186
  renderTemplate,
187
+ replayCommand,
139
188
  resolveContextProfile,
140
189
  resolveVaultPath,
190
+ runReflection,
141
191
  sessionRecapCommand,
142
- setupCommand
192
+ setupCommand,
193
+ syncBdCommand
143
194
  };
@@ -4,7 +4,7 @@ description: "Context resilience - recovery detection, auto-checkpoint, and sess
4
4
  metadata:
5
5
  openclaw:
6
6
  emoji: "🐘"
7
- events: ["gateway:startup", "gateway:heartbeat", "command:new", "session:start", "compaction:memoryFlush"]
7
+ events: ["gateway:startup", "gateway:heartbeat", "command:new", "session:start", "compaction:memoryFlush", "cron.weekly"]
8
8
  requires:
9
9
  bins: ["clawvault"]
10
10
  ---
@@ -18,6 +18,7 @@ Integrates ClawVault's context death resilience into OpenClaw:
18
18
  - **On /new command**: Auto-checkpoints before session reset
19
19
  - **On context compaction**: Forces incremental observation flush before context is lost
20
20
  - **On session start**: Injects relevant vault context for the initial prompt
21
+ - **On weekly cron**: Runs `clawvault reflect` every Sunday midnight (UTC)
21
22
 
22
23
  ## Installation
23
24
 
@@ -63,7 +64,7 @@ Injection format:
63
64
 
64
65
  ### Event Compatibility
65
66
 
66
- The hook accepts canonical OpenClaw events (`gateway:startup`, `gateway:heartbeat`, `command:new`, `session:start`, `compaction:memoryFlush`) and tolerates alias payload shapes (`event`, `eventName`, `name`, `hook`, `trigger`) to remain robust across runtime wrappers.
67
+ The hook accepts canonical OpenClaw events (`gateway:startup`, `gateway:heartbeat`, `command:new`, `session:start`, `compaction:memoryFlush`, `cron.weekly`) and tolerates alias payload shapes (`event`, `eventName`, `name`, `hook`, `trigger`) to remain robust across runtime wrappers.
67
68
 
68
69
  ## No Configuration Needed
69
70
 
@@ -544,6 +544,49 @@ function runActiveObservation(vaultPath, agentId, options = {}) {
544
544
  return true;
545
545
  }
546
546
 
547
+ function extractEventTimestamp(event) {
548
+ const candidates = [
549
+ event?.timestamp,
550
+ event?.scheduledAt,
551
+ event?.time,
552
+ event?.context?.timestamp,
553
+ event?.context?.scheduledAt
554
+ ];
555
+ for (const candidate of candidates) {
556
+ if (!candidate) continue;
557
+ const parsed = new Date(candidate);
558
+ if (!Number.isNaN(parsed.getTime())) {
559
+ return parsed;
560
+ }
561
+ }
562
+ return null;
563
+ }
564
+
565
+ function isSundayMidnightUtc(date) {
566
+ return date.getUTCDay() === 0 && date.getUTCHours() === 0 && date.getUTCMinutes() === 0;
567
+ }
568
+
569
+ async function handleWeeklyReflect(event) {
570
+ const vaultPath = findVaultPath();
571
+ if (!vaultPath) {
572
+ console.log('[clawvault] No vault found, skipping weekly reflection');
573
+ return;
574
+ }
575
+
576
+ const timestamp = extractEventTimestamp(event) || new Date();
577
+ if (!isSundayMidnightUtc(timestamp)) {
578
+ console.log('[clawvault] Weekly reflect skipped (not Sunday midnight UTC)');
579
+ return;
580
+ }
581
+
582
+ const result = runClawvault(['reflect', '-v', vaultPath], { timeoutMs: 120000 });
583
+ if (!result.success) {
584
+ console.warn('[clawvault] Weekly reflection failed');
585
+ return;
586
+ }
587
+ console.log('[clawvault] Weekly reflection complete');
588
+ }
589
+
547
590
  // Handle gateway startup - check for context death
548
591
  async function handleStartup(event) {
549
592
  const vaultPath = findVaultPath();
@@ -724,6 +767,14 @@ const handler = async (event) => {
724
767
  return;
725
768
  }
726
769
 
770
+ if (
771
+ eventMatches(event, 'cron', 'weekly')
772
+ || eventIncludesToken(event, 'cron:weekly')
773
+ ) {
774
+ await handleWeeklyReflect(event);
775
+ return;
776
+ }
777
+
727
778
  if (
728
779
  eventMatches(event, 'gateway', 'heartbeat')
729
780
  || eventMatches(event, 'session', 'heartbeat')
@@ -240,4 +240,24 @@ describe('clawvault hook handler', () => {
240
240
 
241
241
  fs.rmSync(vaultPath, { recursive: true, force: true });
242
242
  });
243
+
244
+ it('runs weekly reflection on cron.weekly at Sunday midnight', async () => {
245
+ const vaultPath = makeVaultFixture();
246
+ process.env.CLAWVAULT_PATH = vaultPath;
247
+ execFileSyncMock.mockReturnValue('');
248
+
249
+ const handler = await loadHandler();
250
+ await handler({
251
+ eventName: 'cron.weekly',
252
+ timestamp: '2026-02-15T00:00:00.000Z'
253
+ });
254
+
255
+ expect(execFileSyncMock).toHaveBeenCalledWith(
256
+ 'clawvault',
257
+ expect.arrayContaining(['reflect', '-v', vaultPath]),
258
+ expect.objectContaining({ shell: false })
259
+ );
260
+
261
+ fs.rmSync(vaultPath, { recursive: true, force: true });
262
+ });
243
263
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawvault",
3
- "version": "2.1.2",
3
+ "version": "2.2.1",
4
4
  "description": "ClawVault™ - 🐘 An elephant never forgets. Structured memory for OpenClaw agents. Context death resilience, Obsidian-compatible markdown, local semantic search.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -29,7 +29,7 @@
29
29
  ]
30
30
  },
31
31
  "scripts": {
32
- "build": "tsup src/index.ts src/commands/entities.ts src/commands/link.ts src/commands/checkpoint.ts src/commands/recover.ts src/commands/status.ts src/commands/template.ts src/commands/setup.ts src/commands/context.ts src/commands/observe.ts src/commands/session-recap.ts src/commands/wake.ts src/commands/sleep.ts src/commands/doctor.ts src/commands/compat.ts src/commands/graph.ts src/commands/shell-init.ts src/commands/repair-session.ts src/lib/entity-index.ts src/lib/auto-linker.ts src/lib/config.ts src/lib/template-engine.ts src/lib/session-utils.ts src/lib/session-repair.ts --format esm --dts --clean",
32
+ "build": "tsup src/index.ts src/commands/entities.ts src/commands/link.ts src/commands/checkpoint.ts src/commands/recover.ts src/commands/status.ts src/commands/template.ts src/commands/setup.ts src/commands/context.ts src/commands/observe.ts src/commands/reflect.ts src/commands/archive.ts src/commands/rebuild.ts src/commands/replay.ts src/commands/migrate-observations.ts src/commands/sync-bd.ts src/commands/session-recap.ts src/commands/wake.ts src/commands/sleep.ts src/commands/doctor.ts src/commands/compat.ts src/commands/graph.ts src/commands/shell-init.ts src/commands/repair-session.ts src/lib/entity-index.ts src/lib/auto-linker.ts src/lib/config.ts src/lib/template-engine.ts src/lib/session-utils.ts src/lib/session-repair.ts --format esm --dts --clean",
33
33
  "dev": "tsup src/index.ts src/commands/*.ts src/lib/*.ts --format esm --dts --watch",
34
34
  "lint": "eslint src",
35
35
  "typecheck": "tsc --noEmit",