clawvault 2.4.2 → 2.4.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.
@@ -80,6 +80,8 @@ export function registerTaskCommands(
80
80
  .option('--priority <priority>', 'New priority')
81
81
  .option('--blocked-by <blocker>', 'What is blocking this task')
82
82
  .option('--due <date>', 'New due date')
83
+ .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
84
+ .option('--reason <reason>', 'Reason for status change')
83
85
  .action(async (slug, options) => {
84
86
  try {
85
87
  const vaultPath = resolveVaultPath(options.vault);
@@ -92,7 +94,9 @@ export function registerTaskCommands(
92
94
  project: options.project,
93
95
  priority: options.priority,
94
96
  blockedBy: options.blockedBy,
95
- due: options.due
97
+ due: options.due,
98
+ confidence: options.confidence,
99
+ reason: options.reason
96
100
  }
97
101
  });
98
102
  } catch (err) {
@@ -106,11 +110,45 @@ export function registerTaskCommands(
106
110
  .command('done <slug>')
107
111
  .description('Mark a task as done')
108
112
  .option('-v, --vault <path>', 'Vault path')
113
+ .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
114
+ .option('--reason <reason>', 'Reason for completion')
109
115
  .action(async (slug, options) => {
110
116
  try {
111
117
  const vaultPath = resolveVaultPath(options.vault);
112
118
  const { taskCommand } = await import('../dist/commands/task.js');
113
- await taskCommand(vaultPath, 'done', { slug });
119
+ await taskCommand(vaultPath, 'done', {
120
+ slug,
121
+ options: {
122
+ confidence: options.confidence,
123
+ reason: options.reason
124
+ }
125
+ });
126
+ } catch (err) {
127
+ console.error(chalk.red(`Error: ${err.message}`));
128
+ process.exit(1);
129
+ }
130
+ });
131
+
132
+ // task transitions
133
+ taskCmd
134
+ .command('transitions [task_id]')
135
+ .description('Show transition history')
136
+ .option('-v, --vault <path>', 'Vault path')
137
+ .option('--agent <id>', 'Filter by agent')
138
+ .option('--failed', 'Show only regression transitions')
139
+ .option('--json', 'Output as JSON')
140
+ .action(async (taskId, options) => {
141
+ try {
142
+ const vaultPath = resolveVaultPath(options.vault);
143
+ const { taskCommand } = await import('../dist/commands/task.js');
144
+ await taskCommand(vaultPath, 'transitions', {
145
+ slug: taskId,
146
+ options: {
147
+ agent: options.agent,
148
+ failed: options.failed,
149
+ json: options.json
150
+ }
151
+ });
114
152
  } catch (err) {
115
153
  console.error(chalk.red(`Error: ${err.message}`));
116
154
  process.exit(1);
@@ -221,6 +259,7 @@ export function registerTaskCommands(
221
259
  .description('View blocked tasks')
222
260
  .option('-v, --vault <path>', 'Vault path')
223
261
  .option('--project <project>', 'Filter by project')
262
+ .option('--escalated', 'Show only escalated tasks (3+ blocked transitions)')
224
263
  .option('--json', 'Output as JSON')
225
264
  .action(async (options) => {
226
265
  try {
@@ -228,6 +267,7 @@ export function registerTaskCommands(
228
267
  const { blockedCommand } = await import('../dist/commands/blocked.js');
229
268
  await blockedCommand(vaultPath, {
230
269
  project: options.project,
270
+ escalated: options.escalated,
231
271
  json: options.json
232
272
  });
233
273
  } catch (err) {
@@ -0,0 +1,105 @@
1
+ // src/lib/transition-ledger.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ var REGRESSION_PAIRS = [
5
+ ["done", "open"],
6
+ ["done", "blocked"],
7
+ ["in-progress", "blocked"]
8
+ ];
9
+ function isRegression(from, to) {
10
+ return REGRESSION_PAIRS.some(([f, t]) => f === from && t === to);
11
+ }
12
+ function getLedgerDir(vaultPath) {
13
+ return path.join(path.resolve(vaultPath), "ledger", "transitions");
14
+ }
15
+ function getTodayLedgerPath(vaultPath) {
16
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
17
+ return path.join(getLedgerDir(vaultPath), `${date}.jsonl`);
18
+ }
19
+ function appendTransition(vaultPath, event) {
20
+ const ledgerDir = getLedgerDir(vaultPath);
21
+ if (!fs.existsSync(ledgerDir)) {
22
+ fs.mkdirSync(ledgerDir, { recursive: true });
23
+ }
24
+ const filePath = getTodayLedgerPath(vaultPath);
25
+ fs.appendFileSync(filePath, JSON.stringify(event) + "\n");
26
+ }
27
+ function buildTransitionEvent(taskId, fromStatus, toStatus, options = {}) {
28
+ const agentId = process.env.OPENCLAW_AGENT_ID || "manual";
29
+ const costTokensRaw = process.env.OPENCLAW_TOKEN_ESTIMATE;
30
+ const costTokens = costTokensRaw ? parseInt(costTokensRaw, 10) : null;
31
+ return {
32
+ task_id: taskId,
33
+ agent_id: agentId,
34
+ from_status: fromStatus,
35
+ to_status: toStatus,
36
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
37
+ confidence: options.confidence ?? (agentId === "manual" ? 1 : 1),
38
+ cost_tokens: costTokens !== null && !isNaN(costTokens) ? costTokens : null,
39
+ reason: options.reason || null
40
+ };
41
+ }
42
+ function readAllTransitions(vaultPath) {
43
+ const ledgerDir = getLedgerDir(vaultPath);
44
+ if (!fs.existsSync(ledgerDir)) return [];
45
+ const files = fs.readdirSync(ledgerDir).filter((f) => f.endsWith(".jsonl")).sort();
46
+ const events = [];
47
+ for (const file of files) {
48
+ const lines = fs.readFileSync(path.join(ledgerDir, file), "utf-8").split("\n").filter((l) => l.trim());
49
+ for (const line of lines) {
50
+ try {
51
+ events.push(JSON.parse(line));
52
+ } catch {
53
+ }
54
+ }
55
+ }
56
+ return events;
57
+ }
58
+ function queryTransitions(vaultPath, filters = {}) {
59
+ let events = readAllTransitions(vaultPath);
60
+ if (filters.taskId) {
61
+ events = events.filter((e) => e.task_id === filters.taskId);
62
+ }
63
+ if (filters.agent) {
64
+ events = events.filter((e) => e.agent_id === filters.agent);
65
+ }
66
+ if (filters.failed) {
67
+ events = events.filter((e) => isRegression(e.from_status, e.to_status));
68
+ }
69
+ return events;
70
+ }
71
+ function countBlockedTransitions(vaultPath, taskId) {
72
+ const events = readAllTransitions(vaultPath);
73
+ return events.filter((e) => e.task_id === taskId && e.to_status === "blocked").length;
74
+ }
75
+ function formatTransitionsTable(events) {
76
+ if (events.length === 0) return "No transitions found.\n";
77
+ const headers = ["TIMESTAMP", "TASK", "FROM\u2192TO", "AGENT", "REASON"];
78
+ const widths = [20, 20, 24, 16, 30];
79
+ let output = headers.map((h, i) => h.padEnd(widths[i])).join(" ") + "\n";
80
+ output += "-".repeat(widths.reduce((a, b) => a + b + 2, 0)) + "\n";
81
+ for (const e of events) {
82
+ const ts = e.timestamp.replace("T", " ").slice(0, 19);
83
+ const taskId = e.task_id.length > widths[1] ? e.task_id.slice(0, widths[1] - 3) + "..." : e.task_id;
84
+ const transition = `${e.from_status} \u2192 ${e.to_status}`;
85
+ const reason = e.reason ? e.reason.length > widths[4] ? e.reason.slice(0, widths[4] - 3) + "..." : e.reason : "-";
86
+ output += [
87
+ ts.padEnd(widths[0]),
88
+ taskId.padEnd(widths[1]),
89
+ transition.padEnd(widths[2]),
90
+ e.agent_id.padEnd(widths[3]),
91
+ reason
92
+ ].join(" ") + "\n";
93
+ }
94
+ return output;
95
+ }
96
+
97
+ export {
98
+ isRegression,
99
+ appendTransition,
100
+ buildTransitionEvent,
101
+ readAllTransitions,
102
+ queryTransitions,
103
+ countBlockedTransitions,
104
+ formatTransitionsTable
105
+ };
@@ -8,6 +8,7 @@ import { Task } from '../lib/task-utils.js';
8
8
  interface BlockedOptions {
9
9
  project?: string;
10
10
  json?: boolean;
11
+ escalated?: boolean;
11
12
  }
12
13
  /**
13
14
  * Get blocked tasks
@@ -11,7 +11,11 @@ function toDateStr(val) {
11
11
  return s;
12
12
  }
13
13
  function blockedList(vaultPath, options = {}) {
14
- return getBlockedTasks(vaultPath, options.project);
14
+ let tasks = getBlockedTasks(vaultPath, options.project);
15
+ if (options.escalated) {
16
+ tasks = tasks.filter((t) => t.frontmatter.escalation === true);
17
+ }
18
+ return tasks;
15
19
  }
16
20
  function formatBlockedList(tasks) {
17
21
  if (tasks.length === 0) {
@@ -27,6 +27,13 @@ interface TaskUpdateOptions {
27
27
  priority?: TaskPriority;
28
28
  blockedBy?: string;
29
29
  due?: string;
30
+ confidence?: number;
31
+ reason?: string;
32
+ }
33
+ interface TaskTransitionsOptions {
34
+ agent?: string;
35
+ failed?: boolean;
36
+ json?: boolean;
30
37
  }
31
38
  interface TaskShowOptions {
32
39
  json?: boolean;
@@ -40,13 +47,20 @@ declare function taskAdd(vaultPath: string, title: string, options?: TaskAddOpti
40
47
  */
41
48
  declare function taskList(vaultPath: string, options?: TaskListOptions): Task[];
42
49
  /**
43
- * Update a task
50
+ * Update a task (with transition logging when status changes)
44
51
  */
45
52
  declare function taskUpdate(vaultPath: string, slug: string, options: TaskUpdateOptions): Task;
46
53
  /**
47
- * Mark a task as done
54
+ * Mark a task as done (with transition logging)
55
+ */
56
+ declare function taskDone(vaultPath: string, slug: string, options?: {
57
+ confidence?: number;
58
+ reason?: string;
59
+ }): Task;
60
+ /**
61
+ * Query task transitions
48
62
  */
49
- declare function taskDone(vaultPath: string, slug: string): Task;
63
+ declare function taskTransitions(vaultPath: string, taskId?: string, options?: TaskTransitionsOptions): string;
50
64
  /**
51
65
  * Show task details
52
66
  */
@@ -62,10 +76,10 @@ declare function formatTaskDetails(task: Task): string;
62
76
  /**
63
77
  * Task command handler for CLI
64
78
  */
65
- declare function taskCommand(vaultPath: string, action: 'add' | 'list' | 'update' | 'done' | 'show', args: {
79
+ declare function taskCommand(vaultPath: string, action: 'add' | 'list' | 'update' | 'done' | 'show' | 'transitions', args: {
66
80
  title?: string;
67
81
  slug?: string;
68
- options?: TaskAddOptions & TaskListOptions & TaskUpdateOptions & TaskShowOptions;
82
+ options?: TaskAddOptions & TaskListOptions & TaskUpdateOptions & TaskShowOptions & TaskTransitionsOptions;
69
83
  }): Promise<void>;
70
84
 
71
- export { type TaskAddOptions, type TaskListOptions, type TaskShowOptions, type TaskUpdateOptions, formatTaskDetails, formatTaskList, taskAdd, taskCommand, taskDone, taskList, taskShow, taskUpdate };
85
+ export { type TaskAddOptions, type TaskListOptions, type TaskShowOptions, type TaskTransitionsOptions, type TaskUpdateOptions, formatTaskDetails, formatTaskList, taskAdd, taskCommand, taskDone, taskList, taskShow, taskTransitions, taskUpdate };
@@ -1,3 +1,10 @@
1
+ import {
2
+ appendTransition,
3
+ buildTransitionEvent,
4
+ countBlockedTransitions,
5
+ formatTransitionsTable,
6
+ queryTransitions
7
+ } from "../chunk-UMMCYTJV.js";
1
8
  import {
2
9
  completeTask,
3
10
  createTask,
@@ -9,6 +16,8 @@ import {
9
16
  } from "../chunk-DEFBIVQ3.js";
10
17
 
11
18
  // src/commands/task.ts
19
+ import matter from "gray-matter";
20
+ import * as fs from "fs";
12
21
  function taskAdd(vaultPath, title, options = {}) {
13
22
  return createTask(vaultPath, title, {
14
23
  owner: options.owner,
@@ -32,7 +41,9 @@ function taskList(vaultPath, options = {}) {
32
41
  return listTasks(vaultPath, filters);
33
42
  }
34
43
  function taskUpdate(vaultPath, slug, options) {
35
- return updateTask(vaultPath, slug, {
44
+ const before = readTask(vaultPath, slug);
45
+ const oldStatus = before?.frontmatter.status;
46
+ const task = updateTask(vaultPath, slug, {
36
47
  status: options.status,
37
48
  owner: options.owner,
38
49
  project: options.project,
@@ -40,9 +51,52 @@ function taskUpdate(vaultPath, slug, options) {
40
51
  blocked_by: options.blockedBy,
41
52
  due: options.due
42
53
  });
54
+ if (options.status && oldStatus && options.status !== oldStatus) {
55
+ emitTransition(vaultPath, slug, oldStatus, options.status, options);
56
+ }
57
+ return task;
58
+ }
59
+ function taskDone(vaultPath, slug, options = {}) {
60
+ const before = readTask(vaultPath, slug);
61
+ const oldStatus = before?.frontmatter.status;
62
+ const task = completeTask(vaultPath, slug);
63
+ if (oldStatus && oldStatus !== "done") {
64
+ emitTransition(vaultPath, slug, oldStatus, "done", options);
65
+ }
66
+ return task;
43
67
  }
44
- function taskDone(vaultPath, slug) {
45
- return completeTask(vaultPath, slug);
68
+ function emitTransition(vaultPath, slug, fromStatus, toStatus, options = {}) {
69
+ const event = buildTransitionEvent(slug, fromStatus, toStatus, {
70
+ confidence: options.confidence,
71
+ reason: options.reason
72
+ });
73
+ appendTransition(vaultPath, event);
74
+ if (toStatus === "blocked") {
75
+ const blockedCount = countBlockedTransitions(vaultPath, slug);
76
+ if (blockedCount >= 3) {
77
+ markEscalation(vaultPath, slug);
78
+ }
79
+ }
80
+ }
81
+ function markEscalation(vaultPath, slug) {
82
+ const task = readTask(vaultPath, slug);
83
+ if (!task) return;
84
+ const raw = fs.readFileSync(task.path, "utf-8");
85
+ const { data, content } = matter(raw);
86
+ if (data.escalation) return;
87
+ data.escalation = true;
88
+ fs.writeFileSync(task.path, matter.stringify(content, data));
89
+ }
90
+ function taskTransitions(vaultPath, taskId, options = {}) {
91
+ const events = queryTransitions(vaultPath, {
92
+ taskId,
93
+ agent: options.agent,
94
+ failed: options.failed
95
+ });
96
+ if (options.json) {
97
+ return JSON.stringify(events, null, 2);
98
+ }
99
+ return formatTransitionsTable(events);
46
100
  }
47
101
  function taskShow(vaultPath, slug) {
48
102
  return readTask(vaultPath, slug);
@@ -154,10 +208,22 @@ async function taskCommand(vaultPath, action, args) {
154
208
  if (!args.slug) {
155
209
  throw new Error("Task slug is required for done");
156
210
  }
157
- const task = taskDone(vaultPath, args.slug);
211
+ const task = taskDone(vaultPath, args.slug, {
212
+ confidence: options.confidence,
213
+ reason: options.reason
214
+ });
158
215
  console.log(`\u2713 Completed task: ${task.slug}`);
159
216
  break;
160
217
  }
218
+ case "transitions": {
219
+ const output = taskTransitions(vaultPath, args.slug, {
220
+ agent: options.agent,
221
+ failed: options.failed,
222
+ json: options.json
223
+ });
224
+ console.log(output);
225
+ break;
226
+ }
161
227
  case "show": {
162
228
  if (!args.slug) {
163
229
  throw new Error("Task slug is required for show");
@@ -185,5 +251,6 @@ export {
185
251
  taskDone,
186
252
  taskList,
187
253
  taskShow,
254
+ taskTransitions,
188
255
  taskUpdate
189
256
  };
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export { MigrateObservationsOptions, MigrateObservationsResult, migrateObservati
14
14
  export { SyncBdCommandOptions, registerSyncBdCommand, syncBdCommand } from './commands/sync-bd.js';
15
15
  export { SessionRecapFormat, SessionRecapOptions, SessionRecapResult, SessionTurn, buildSessionRecap, formatSessionRecapMarkdown, sessionRecapCommand } from './commands/session-recap.js';
16
16
  export { findNearestVaultPath, getVaultPath, resolveVaultPath } from './lib/config.js';
17
+ import { TaskStatus } from './lib/task-utils.js';
17
18
  export { CLAWVAULT_SERVE_PATH, DEFAULT_SERVE_PORT, ServeInstance, TailscalePeer, TailscaleServeConfig, TailscaleStatus, TailscaleSyncOptions, TailscaleSyncResult, VaultFileEntry, VaultManifest, checkPeerClawVault, compareManifests, configureTailscaleServe, discoverClawVaultPeers, fetchRemoteFile, fetchRemoteManifest, findPeer, generateVaultManifest, getOnlinePeers, getTailscaleStatus, getTailscaleVersion, hasTailscale, pushFileToRemote, resolvePeerIP, serveVault, stopTailscaleServe, syncWithPeer } from './lib/tailscale.js';
18
19
  export { TailscaleDiscoverCommandOptions, TailscaleServeCommandOptions, TailscaleStatusCommandOptions, TailscaleSyncCommandOptions, registerTailscaleCommands, registerTailscaleDiscoverCommand, registerTailscaleServeCommand, registerTailscaleStatusCommand, registerTailscaleSyncCommand, tailscaleDiscoverCommand, tailscaleServeCommand, tailscaleStatusCommand, tailscaleSyncCommand } from './commands/tailscale.js';
19
20
  export { TemplateVariables, buildTemplateVariables, renderTemplate } from './lib/template-engine.js';
@@ -344,6 +345,54 @@ declare function getMemoryGraph(vaultPath: string, options?: {
344
345
  refresh?: boolean;
345
346
  }): Promise<MemoryGraph>;
346
347
 
348
+ /**
349
+ * Transition Ledger for ClawVault
350
+ * Logs task status transitions to JSONL files and supports querying.
351
+ */
352
+
353
+ interface TransitionEvent {
354
+ task_id: string;
355
+ agent_id: string;
356
+ from_status: TaskStatus;
357
+ to_status: TaskStatus;
358
+ timestamp: string;
359
+ confidence: number;
360
+ cost_tokens: number | null;
361
+ reason: string | null;
362
+ }
363
+ declare function isRegression(from: TaskStatus, to: TaskStatus): boolean;
364
+ /**
365
+ * Append a transition event to the ledger
366
+ */
367
+ declare function appendTransition(vaultPath: string, event: TransitionEvent): void;
368
+ /**
369
+ * Build a transition event from context
370
+ */
371
+ declare function buildTransitionEvent(taskId: string, fromStatus: TaskStatus, toStatus: TaskStatus, options?: {
372
+ confidence?: number;
373
+ reason?: string;
374
+ }): TransitionEvent;
375
+ /**
376
+ * Read all transition events from all ledger files
377
+ */
378
+ declare function readAllTransitions(vaultPath: string): TransitionEvent[];
379
+ /**
380
+ * Query transitions with filters
381
+ */
382
+ declare function queryTransitions(vaultPath: string, filters?: {
383
+ taskId?: string;
384
+ agent?: string;
385
+ failed?: boolean;
386
+ }): TransitionEvent[];
387
+ /**
388
+ * Count blocked transitions for a task
389
+ */
390
+ declare function countBlockedTransitions(vaultPath: string, taskId: string): number;
391
+ /**
392
+ * Format transitions as a table string
393
+ */
394
+ declare function formatTransitionsTable(events: TransitionEvent[]): string;
395
+
347
396
  interface ObserverCompressor {
348
397
  compress(messages: string[], existingObservations: string): Promise<string>;
349
398
  }
@@ -548,4 +597,4 @@ declare function runReflection(options: ReflectOptions): Promise<ReflectResult>;
548
597
  declare const VERSION: string;
549
598
  declare function registerCommanderCommands(program: Command): Command;
550
599
 
551
- 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 };
600
+ 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, type TransitionEvent, VERSION, VaultConfig, appendTransition, archiveObservations, buildOrUpdateMemoryGraphIndex, buildTransitionEvent, countBlockedTransitions, createVault, extractTags, extractWikiLinks, findVault, formatTransitionsTable, getMemoryGraph, hasQmd, isRegression, loadMemoryGraphIndex, parseSessionFile, qmdEmbed, qmdUpdate, queryTransitions, readAllTransitions, registerCommanderCommands, runReflection };
package/dist/index.js CHANGED
@@ -35,6 +35,15 @@ import {
35
35
  syncWithPeer
36
36
  } from "./chunk-4GBPTBFJ.js";
37
37
  import "./chunk-CLE2HHNT.js";
38
+ import {
39
+ appendTransition,
40
+ buildTransitionEvent,
41
+ countBlockedTransitions,
42
+ formatTransitionsTable,
43
+ isRegression,
44
+ queryTransitions,
45
+ readAllTransitions
46
+ } from "./chunk-UMMCYTJV.js";
38
47
  import {
39
48
  buildTemplateVariables,
40
49
  renderTemplate
@@ -179,12 +188,14 @@ export {
179
188
  SessionWatcher,
180
189
  TYPE_TO_CATEGORY,
181
190
  VERSION,
191
+ appendTransition,
182
192
  archiveCommand,
183
193
  archiveObservations,
184
194
  buildContext,
185
195
  buildOrUpdateMemoryGraphIndex,
186
196
  buildSessionRecap,
187
197
  buildTemplateVariables,
198
+ buildTransitionEvent,
188
199
  checkOpenClawCompatibility,
189
200
  checkPeerClawVault,
190
201
  compareManifests,
@@ -192,6 +203,7 @@ export {
192
203
  compatibilityExitCode,
193
204
  configureTailscaleServe,
194
205
  contextCommand,
206
+ countBlockedTransitions,
195
207
  createVault,
196
208
  discoverClawVaultPeers,
197
209
  extractTags,
@@ -203,6 +215,7 @@ export {
203
215
  findVault,
204
216
  formatContextMarkdown,
205
217
  formatSessionRecapMarkdown,
218
+ formatTransitionsTable,
206
219
  generateVaultManifest,
207
220
  getMemoryGraph,
208
221
  getOnlinePeers,
@@ -214,6 +227,7 @@ export {
214
227
  hasQmd,
215
228
  hasTailscale,
216
229
  inferContextProfile,
230
+ isRegression,
217
231
  loadMemoryGraphIndex,
218
232
  migrateObservations,
219
233
  migrateObservationsCommand,
@@ -223,6 +237,8 @@ export {
223
237
  pushFileToRemote,
224
238
  qmdEmbed,
225
239
  qmdUpdate,
240
+ queryTransitions,
241
+ readAllTransitions,
226
242
  rebuildCommand,
227
243
  reflectCommand,
228
244
  registerArchiveCommand,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clawvault",
3
- "version": "2.4.2",
4
- "description": "Structured memory system for AI agents — typed storage, knowledge graph, task management, and Obsidian dashboards. An elephant never forgets. 🐘",
3
+ "version": "2.4.4",
4
+ "description": "Structured memory system for AI agents — typed storage, knowledge graph, context profiles, canvas dashboards, neural graph themes, and Obsidian-native task views. An elephant never forgets. 🐘",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",