clawvault 2.6.0 → 3.0.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 (232) hide show
  1. package/bin/command-registration.test.js +1 -3
  2. package/bin/register-core-commands.js +10 -23
  3. package/bin/register-maintenance-commands.js +3 -20
  4. package/bin/register-query-commands.js +23 -0
  5. package/bin/register-task-commands.js +1 -18
  6. package/bin/register-task-commands.test.js +0 -16
  7. package/bin/register-vault-operations-commands.js +1 -29
  8. package/dist/{chunk-QVMXF7FY.js → chunk-3D6BCTP6.js} +39 -1
  9. package/dist/{chunk-R2MIW5G7.js → chunk-3DHXQHYG.js} +1 -1
  10. package/dist/{chunk-Q2J5YTUF.js → chunk-3NSBOUT3.js} +73 -36
  11. package/dist/chunk-3RG5ZIWI.js +10 -0
  12. package/dist/{chunk-AZYOKJYC.js → chunk-62YTUT6J.js} +2 -2
  13. package/dist/chunk-6U6MK36V.js +205 -0
  14. package/dist/{chunk-4QYGFWRM.js → chunk-7R7O6STJ.js} +4 -4
  15. package/dist/{chunk-VXEOHTSL.js → chunk-C7OK5WKP.js} +4 -4
  16. package/dist/chunk-CMB7UL7C.js +327 -0
  17. package/dist/chunk-DEFFDRVP.js +938 -0
  18. package/dist/{chunk-K3CDT7IH.js → chunk-E7MFQB6D.js} +61 -20
  19. package/dist/{chunk-ME37YNW3.js → chunk-F2JEUD4J.js} +6 -4
  20. package/dist/chunk-GAJV4IGR.js +82 -0
  21. package/dist/chunk-GQSLDZTS.js +560 -0
  22. package/dist/{chunk-4OXMU5S2.js → chunk-GUKMRGM7.js} +1 -1
  23. package/dist/{chunk-YOSEUUNB.js → chunk-H34S76MB.js} +6 -6
  24. package/dist/{chunk-4TE4JMLA.js → chunk-JY6FYXIT.js} +10 -5
  25. package/dist/chunk-K234IDRJ.js +1073 -0
  26. package/dist/{chunk-IEVLHNLU.js → chunk-LNJA2UGL.js} +86 -9
  27. package/dist/{chunk-MFAWT5O5.js → chunk-LYHGEHXG.js} +1 -0
  28. package/dist/chunk-MFM6K7PU.js +374 -0
  29. package/dist/{chunk-QWQ3TIKS.js → chunk-N2AXRYLC.js} +1 -1
  30. package/dist/chunk-PAH27GSN.js +108 -0
  31. package/dist/{chunk-OIWVQYQF.js → chunk-QBLMXKF2.js} +1 -1
  32. package/dist/{chunk-FHFUXL6G.js → chunk-QK3UCXWL.js} +2 -2
  33. package/dist/{chunk-2YDBJS7M.js → chunk-SJSFRIYS.js} +1 -1
  34. package/dist/{chunk-GSD4ALSI.js → chunk-U55BGUAU.js} +2 -2
  35. package/dist/{chunk-PBEE567J.js → chunk-VGLOTGAS.js} +1 -1
  36. package/dist/{chunk-F55HGNU4.js → chunk-WAZ3NLWL.js} +47 -0
  37. package/dist/{chunk-KL4NAOMO.js → chunk-WGRQ6HDV.js} +1 -1
  38. package/dist/{chunk-UEOUADMO.js → chunk-YKTA5JOJ.js} +13 -10
  39. package/dist/{chunk-XAVB4GB4.js → chunk-ZVVFWOLW.js} +4 -4
  40. package/dist/cli/index.cjs +10033 -0
  41. package/dist/cli/index.d.cts +5 -0
  42. package/dist/cli/index.js +20 -18
  43. package/dist/commands/archive.cjs +287 -0
  44. package/dist/commands/archive.d.cts +11 -0
  45. package/dist/commands/archive.js +1 -0
  46. package/dist/commands/backlog.cjs +721 -0
  47. package/dist/commands/backlog.d.cts +53 -0
  48. package/dist/commands/backlog.js +3 -2
  49. package/dist/commands/blocked.cjs +204 -0
  50. package/dist/commands/blocked.d.cts +26 -0
  51. package/dist/commands/blocked.js +3 -2
  52. package/dist/commands/checkpoint.cjs +244 -0
  53. package/dist/commands/checkpoint.d.cts +41 -0
  54. package/dist/commands/checkpoint.js +2 -1
  55. package/dist/commands/compat.cjs +369 -0
  56. package/dist/commands/compat.d.cts +28 -0
  57. package/dist/commands/compat.js +2 -1
  58. package/dist/commands/context.cjs +2989 -0
  59. package/dist/commands/context.d.cts +2 -0
  60. package/dist/commands/context.js +5 -4
  61. package/dist/commands/doctor.cjs +3062 -0
  62. package/dist/commands/doctor.d.cts +21 -0
  63. package/dist/commands/doctor.d.ts +6 -1
  64. package/dist/commands/doctor.js +13 -11
  65. package/dist/commands/embed.cjs +232 -0
  66. package/dist/commands/embed.d.cts +17 -0
  67. package/dist/commands/embed.js +5 -2
  68. package/dist/commands/entities.cjs +141 -0
  69. package/dist/commands/entities.d.cts +7 -0
  70. package/dist/commands/entities.js +1 -0
  71. package/dist/commands/graph.cjs +501 -0
  72. package/dist/commands/graph.d.cts +21 -0
  73. package/dist/commands/graph.js +1 -0
  74. package/dist/commands/inject.cjs +1636 -0
  75. package/dist/commands/inject.d.cts +2 -0
  76. package/dist/commands/inject.d.ts +1 -1
  77. package/dist/commands/inject.js +4 -2
  78. package/dist/commands/kanban.cjs +884 -0
  79. package/dist/commands/kanban.d.cts +63 -0
  80. package/dist/commands/kanban.js +4 -3
  81. package/dist/commands/link.cjs +965 -0
  82. package/dist/commands/link.d.cts +11 -0
  83. package/dist/commands/link.js +1 -0
  84. package/dist/commands/migrate-observations.cjs +362 -0
  85. package/dist/commands/migrate-observations.d.cts +19 -0
  86. package/dist/commands/migrate-observations.js +3 -2
  87. package/dist/commands/observe.cjs +4099 -0
  88. package/dist/commands/observe.d.cts +23 -0
  89. package/dist/commands/observe.d.ts +1 -0
  90. package/dist/commands/observe.js +11 -9
  91. package/dist/commands/project.cjs +1341 -0
  92. package/dist/commands/project.d.cts +85 -0
  93. package/dist/commands/project.js +5 -4
  94. package/dist/commands/rebuild.cjs +3136 -0
  95. package/dist/commands/rebuild.d.cts +11 -0
  96. package/dist/commands/rebuild.js +10 -8
  97. package/dist/commands/recover.cjs +361 -0
  98. package/dist/commands/recover.d.cts +38 -0
  99. package/dist/commands/recover.js +3 -2
  100. package/dist/commands/reflect.cjs +1008 -0
  101. package/dist/commands/reflect.d.cts +11 -0
  102. package/dist/commands/reflect.js +6 -4
  103. package/dist/commands/repair-session.cjs +457 -0
  104. package/dist/commands/repair-session.d.cts +38 -0
  105. package/dist/commands/repair-session.js +1 -0
  106. package/dist/commands/replay.cjs +4103 -0
  107. package/dist/commands/replay.d.cts +16 -0
  108. package/dist/commands/replay.js +12 -10
  109. package/dist/commands/session-recap.cjs +353 -0
  110. package/dist/commands/session-recap.d.cts +27 -0
  111. package/dist/commands/session-recap.js +1 -0
  112. package/dist/commands/setup.cjs +1345 -0
  113. package/dist/commands/setup.d.cts +100 -0
  114. package/dist/commands/setup.d.ts +90 -2
  115. package/dist/commands/setup.js +21 -2
  116. package/dist/commands/shell-init.cjs +75 -0
  117. package/dist/commands/shell-init.d.cts +7 -0
  118. package/dist/commands/shell-init.js +2 -0
  119. package/dist/commands/sleep.cjs +6028 -0
  120. package/dist/commands/sleep.d.cts +36 -0
  121. package/dist/commands/sleep.d.ts +1 -1
  122. package/dist/commands/sleep.js +17 -15
  123. package/dist/commands/status.cjs +2736 -0
  124. package/dist/commands/status.d.cts +52 -0
  125. package/dist/commands/status.js +12 -10
  126. package/dist/commands/tailscale.cjs +1532 -0
  127. package/dist/commands/tailscale.d.cts +52 -0
  128. package/dist/commands/tailscale.js +1 -0
  129. package/dist/commands/task.cjs +1236 -0
  130. package/dist/commands/task.d.cts +97 -0
  131. package/dist/commands/task.js +4 -3
  132. package/dist/commands/template.cjs +457 -0
  133. package/dist/commands/template.d.cts +36 -0
  134. package/dist/commands/template.js +2 -1
  135. package/dist/commands/wake.cjs +2626 -0
  136. package/dist/commands/wake.d.cts +22 -0
  137. package/dist/commands/wake.d.ts +1 -1
  138. package/dist/commands/wake.js +12 -11
  139. package/dist/context-BUGaWpyL.d.cts +46 -0
  140. package/dist/index.cjs +14526 -0
  141. package/dist/index.d.cts +858 -0
  142. package/dist/index.d.ts +192 -7
  143. package/dist/index.js +101 -75
  144. package/dist/{inject-x65KXWPk.d.ts → inject-Bzi5E-By.d.cts} +1 -1
  145. package/dist/inject-Bzi5E-By.d.ts +137 -0
  146. package/dist/lib/auto-linker.cjs +176 -0
  147. package/dist/lib/auto-linker.d.cts +26 -0
  148. package/dist/lib/auto-linker.js +1 -0
  149. package/dist/lib/canvas-layout.cjs +136 -0
  150. package/dist/lib/canvas-layout.d.cts +31 -0
  151. package/dist/lib/canvas-layout.d.ts +16 -100
  152. package/dist/lib/canvas-layout.js +78 -20
  153. package/dist/lib/config.cjs +78 -0
  154. package/dist/lib/config.d.cts +11 -0
  155. package/dist/lib/config.js +1 -0
  156. package/dist/lib/entity-index.cjs +84 -0
  157. package/dist/lib/entity-index.d.cts +26 -0
  158. package/dist/lib/entity-index.js +1 -0
  159. package/dist/lib/project-utils.cjs +864 -0
  160. package/dist/lib/project-utils.d.cts +97 -0
  161. package/dist/lib/project-utils.js +4 -3
  162. package/dist/lib/session-repair.cjs +239 -0
  163. package/dist/lib/session-repair.d.cts +110 -0
  164. package/dist/lib/session-repair.js +1 -0
  165. package/dist/lib/session-utils.cjs +209 -0
  166. package/dist/lib/session-utils.d.cts +63 -0
  167. package/dist/lib/session-utils.js +1 -0
  168. package/dist/lib/tailscale.cjs +1183 -0
  169. package/dist/lib/tailscale.d.cts +225 -0
  170. package/dist/lib/tailscale.js +1 -0
  171. package/dist/lib/task-utils.cjs +1137 -0
  172. package/dist/lib/task-utils.d.cts +208 -0
  173. package/dist/lib/task-utils.js +3 -2
  174. package/dist/lib/template-engine.cjs +47 -0
  175. package/dist/lib/template-engine.d.cts +11 -0
  176. package/dist/lib/template-engine.js +1 -0
  177. package/dist/lib/webdav.cjs +568 -0
  178. package/dist/lib/webdav.d.cts +109 -0
  179. package/dist/lib/webdav.js +1 -0
  180. package/dist/plugin/index.cjs +1907 -0
  181. package/dist/plugin/index.d.cts +36 -0
  182. package/dist/plugin/index.d.ts +36 -0
  183. package/dist/plugin/index.js +572 -0
  184. package/dist/plugin/inject.cjs +356 -0
  185. package/dist/plugin/inject.d.cts +54 -0
  186. package/dist/plugin/inject.d.ts +54 -0
  187. package/dist/plugin/inject.js +17 -0
  188. package/dist/plugin/observe.cjs +631 -0
  189. package/dist/plugin/observe.d.cts +39 -0
  190. package/dist/plugin/observe.d.ts +39 -0
  191. package/dist/plugin/observe.js +18 -0
  192. package/dist/plugin/templates.cjs +593 -0
  193. package/dist/plugin/templates.d.cts +52 -0
  194. package/dist/plugin/templates.d.ts +52 -0
  195. package/dist/plugin/templates.js +25 -0
  196. package/dist/plugin/types.cjs +18 -0
  197. package/dist/plugin/types.d.cts +209 -0
  198. package/dist/plugin/types.d.ts +209 -0
  199. package/dist/plugin/types.js +0 -0
  200. package/dist/plugin/vault.cjs +927 -0
  201. package/dist/plugin/vault.d.cts +68 -0
  202. package/dist/plugin/vault.d.ts +68 -0
  203. package/dist/plugin/vault.js +22 -0
  204. package/dist/{types-C74wgGL1.d.ts → types-Y2_Um2Ls.d.cts} +44 -1
  205. package/dist/types-Y2_Um2Ls.d.ts +205 -0
  206. package/hooks/clawvault/handler.js +70 -7
  207. package/hooks/clawvault/handler.test.js +91 -0
  208. package/openclaw.plugin.json +56 -0
  209. package/package.json +17 -7
  210. package/templates/memory-event.md +67 -0
  211. package/templates/party.md +63 -0
  212. package/templates/primitive-registry.yaml +551 -0
  213. package/templates/run.md +68 -0
  214. package/templates/trigger.md +68 -0
  215. package/templates/workspace.md +50 -0
  216. package/dashboard/lib/graph-diff.js +0 -104
  217. package/dashboard/lib/graph-diff.test.js +0 -75
  218. package/dashboard/lib/vault-parser.js +0 -556
  219. package/dashboard/lib/vault-parser.test.js +0 -254
  220. package/dashboard/public/app.js +0 -796
  221. package/dashboard/public/index.html +0 -52
  222. package/dashboard/public/styles.css +0 -221
  223. package/dashboard/server.js +0 -374
  224. package/dist/chunk-HA5M6KJB.js +0 -33
  225. package/dist/chunk-MAKNAHAW.js +0 -375
  226. package/dist/chunk-MDIH26GC.js +0 -183
  227. package/dist/chunk-MGDEINGP.js +0 -99
  228. package/dist/chunk-RVYA52PY.js +0 -363
  229. package/dist/commands/canvas.d.ts +0 -15
  230. package/dist/commands/canvas.js +0 -199
  231. package/dist/commands/sync-bd.d.ts +0 -10
  232. package/dist/commands/sync-bd.js +0 -9
@@ -0,0 +1,68 @@
1
+ import { Observation } from './observe.cjs';
2
+
3
+ /**
4
+ * Template-Aware Vault File Writing for ClawVault
5
+ *
6
+ * Writes vault files with proper frontmatter based on template schemas.
7
+ * Validates enum fields, applies defaults, and adds timestamps.
8
+ */
9
+
10
+ interface WriteOptions {
11
+ primitiveType?: string;
12
+ title?: string;
13
+ content?: string;
14
+ extraFields?: Record<string, unknown>;
15
+ source?: string;
16
+ sessionId?: string;
17
+ directory?: string;
18
+ filename?: string;
19
+ overwrite?: boolean;
20
+ }
21
+ interface WriteResult {
22
+ success: boolean;
23
+ path: string;
24
+ primitiveType: string;
25
+ errors: string[];
26
+ created: boolean;
27
+ updated: boolean;
28
+ }
29
+ interface LedgerEntry {
30
+ timestamp: Date;
31
+ category: string;
32
+ actor?: string;
33
+ content: string;
34
+ primitiveType?: string;
35
+ tags?: string[];
36
+ }
37
+ declare function writeVaultFile(vaultPath: string, options: WriteOptions): WriteResult;
38
+ declare function writeObservation(vaultPath: string, observation: Observation, options?: {
39
+ source?: string;
40
+ sessionId?: string;
41
+ }): WriteResult;
42
+ declare function writeObservations(vaultPath: string, observations: Observation[], options?: {
43
+ source?: string;
44
+ sessionId?: string;
45
+ }): WriteResult[];
46
+ declare function appendToLedger(vaultPath: string, entry: LedgerEntry): void;
47
+ declare function appendObservationToLedger(vaultPath: string, observation: Observation, actor?: string): void;
48
+ interface BatchWriteResult {
49
+ total: number;
50
+ successful: number;
51
+ failed: number;
52
+ results: WriteResult[];
53
+ }
54
+ declare function batchWriteObservations(vaultPath: string, observations: Observation[], options?: {
55
+ source?: string;
56
+ sessionId?: string;
57
+ writeLedger?: boolean;
58
+ writeFiles?: boolean;
59
+ actor?: string;
60
+ }): BatchWriteResult;
61
+ declare function ensureVaultStructure(vaultPath: string): void;
62
+ declare function getVaultStats(vaultPath: string): {
63
+ directories: string[];
64
+ fileCount: number;
65
+ primitiveTypes: Record<string, number>;
66
+ };
67
+
68
+ export { type BatchWriteResult, type LedgerEntry, type WriteOptions, type WriteResult, appendObservationToLedger, appendToLedger, batchWriteObservations, ensureVaultStructure, getVaultStats, writeObservation, writeObservations, writeVaultFile };
@@ -0,0 +1,68 @@
1
+ import { Observation } from './observe.js';
2
+
3
+ /**
4
+ * Template-Aware Vault File Writing for ClawVault
5
+ *
6
+ * Writes vault files with proper frontmatter based on template schemas.
7
+ * Validates enum fields, applies defaults, and adds timestamps.
8
+ */
9
+
10
+ interface WriteOptions {
11
+ primitiveType?: string;
12
+ title?: string;
13
+ content?: string;
14
+ extraFields?: Record<string, unknown>;
15
+ source?: string;
16
+ sessionId?: string;
17
+ directory?: string;
18
+ filename?: string;
19
+ overwrite?: boolean;
20
+ }
21
+ interface WriteResult {
22
+ success: boolean;
23
+ path: string;
24
+ primitiveType: string;
25
+ errors: string[];
26
+ created: boolean;
27
+ updated: boolean;
28
+ }
29
+ interface LedgerEntry {
30
+ timestamp: Date;
31
+ category: string;
32
+ actor?: string;
33
+ content: string;
34
+ primitiveType?: string;
35
+ tags?: string[];
36
+ }
37
+ declare function writeVaultFile(vaultPath: string, options: WriteOptions): WriteResult;
38
+ declare function writeObservation(vaultPath: string, observation: Observation, options?: {
39
+ source?: string;
40
+ sessionId?: string;
41
+ }): WriteResult;
42
+ declare function writeObservations(vaultPath: string, observations: Observation[], options?: {
43
+ source?: string;
44
+ sessionId?: string;
45
+ }): WriteResult[];
46
+ declare function appendToLedger(vaultPath: string, entry: LedgerEntry): void;
47
+ declare function appendObservationToLedger(vaultPath: string, observation: Observation, actor?: string): void;
48
+ interface BatchWriteResult {
49
+ total: number;
50
+ successful: number;
51
+ failed: number;
52
+ results: WriteResult[];
53
+ }
54
+ declare function batchWriteObservations(vaultPath: string, observations: Observation[], options?: {
55
+ source?: string;
56
+ sessionId?: string;
57
+ writeLedger?: boolean;
58
+ writeFiles?: boolean;
59
+ actor?: string;
60
+ }): BatchWriteResult;
61
+ declare function ensureVaultStructure(vaultPath: string): void;
62
+ declare function getVaultStats(vaultPath: string): {
63
+ directories: string[];
64
+ fileCount: number;
65
+ primitiveTypes: Record<string, number>;
66
+ };
67
+
68
+ export { type BatchWriteResult, type LedgerEntry, type WriteOptions, type WriteResult, appendObservationToLedger, appendToLedger, batchWriteObservations, ensureVaultStructure, getVaultStats, writeObservation, writeObservations, writeVaultFile };
@@ -0,0 +1,22 @@
1
+ import {
2
+ appendObservationToLedger,
3
+ appendToLedger,
4
+ batchWriteObservations,
5
+ ensureVaultStructure,
6
+ getVaultStats,
7
+ writeObservation,
8
+ writeObservations,
9
+ writeVaultFile
10
+ } from "../chunk-MFM6K7PU.js";
11
+ import "../chunk-GQSLDZTS.js";
12
+ import "../chunk-3RG5ZIWI.js";
13
+ export {
14
+ appendObservationToLedger,
15
+ appendToLedger,
16
+ batchWriteObservations,
17
+ ensureVaultStructure,
18
+ getVaultStats,
19
+ writeObservation,
20
+ writeObservations,
21
+ writeVaultFile
22
+ };
@@ -70,6 +70,49 @@ interface SearchOptions {
70
70
  fullContent?: boolean;
71
71
  /** Boost recent documents in ranking */
72
72
  temporalBoost?: boolean;
73
+ /**
74
+ * v2.7 — Enable chunk-level BM25 pre-filtering before semantic search.
75
+ * Chunks documents into ~600-char sentence windows and ranks chunks by
76
+ * keyword overlap so that relevant content deep in long documents isn't
77
+ * silently dropped by fixed-N embedding limits.
78
+ */
79
+ chunkPrefilter?: boolean;
80
+ /**
81
+ * v2.7 — Exhaustive threshold-based retrieval for aggregation queries.
82
+ * Instead of a fixed top_k, keeps pulling results until the normalised
83
+ * relevance score drops below this threshold (0-1). Set to e.g. 0.01
84
+ * for aggregation / "list all" queries. Overrides `limit` when set.
85
+ */
86
+ relevanceThreshold?: number;
87
+ /**
88
+ * v2.7 — Maximum results when using relevanceThreshold.
89
+ * Prevents runaway result sets. Default 40.
90
+ */
91
+ thresholdMaxResults?: number;
92
+ }
93
+ /**
94
+ * v2.7 — A date reference extracted from document content at ingest time.
95
+ */
96
+ interface ExtractedDate {
97
+ /** ISO date string (YYYY-MM-DD) or "duration:<value>" */
98
+ date: string;
99
+ /** Surrounding context snippet (~150 chars) */
100
+ context: string;
101
+ /** Document id the date was extracted from */
102
+ documentId: string;
103
+ }
104
+ /**
105
+ * v2.7 — An extracted user preference from conversation content.
106
+ */
107
+ interface ExtractedPreference {
108
+ /** The preference category (tool, hobby, brand, etc.) */
109
+ category: string;
110
+ /** The preference value */
111
+ value: string;
112
+ /** Document id it was extracted from */
113
+ documentId: string;
114
+ /** Surrounding context snippet */
115
+ context: string;
73
116
  }
74
117
  interface StoreOptions {
75
118
  /** Category to store in */
@@ -159,4 +202,4 @@ interface SessionRecap {
159
202
  }
160
203
  declare const DEFAULT_CONFIG: Partial<VaultConfig>;
161
204
 
162
- export { type Category as C, type Document as D, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e, DEFAULT_CATEGORIES as f, DEFAULT_CONFIG as g, MEMORY_TYPES as h, type VaultMeta as i };
205
+ export { type Category as C, type Document as D, type ExtractedDate as E, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e, type ExtractedPreference as f, DEFAULT_CATEGORIES as g, DEFAULT_CONFIG as h, MEMORY_TYPES as i, type VaultMeta as j };
@@ -0,0 +1,205 @@
1
+ /**
2
+ * ClawVault Types - The elephant's memory structure
3
+ */
4
+ interface VaultConfig {
5
+ /** Root path of the vault */
6
+ path: string;
7
+ /** Name of the vault */
8
+ name: string;
9
+ /** Categories to create on init */
10
+ categories: string[];
11
+ /** qmd collection name (defaults to vault name if not set) */
12
+ qmdCollection?: string;
13
+ /** Root path for qmd collection (defaults to vault path) */
14
+ qmdRoot?: string;
15
+ /** Custom templates path (optional) */
16
+ templatesPath?: string;
17
+ }
18
+ interface VaultMeta {
19
+ name: string;
20
+ version: string;
21
+ created: string;
22
+ lastUpdated: string;
23
+ categories: string[];
24
+ documentCount: number;
25
+ /** qmd collection name (defaults to vault name if not set) */
26
+ qmdCollection?: string;
27
+ /** Root path for qmd collection (defaults to vault path) */
28
+ qmdRoot?: string;
29
+ }
30
+ interface Document {
31
+ /** Unique ID (relative path without extension) */
32
+ id: string;
33
+ /** Full file path */
34
+ path: string;
35
+ /** Category (folder name) */
36
+ category: string;
37
+ /** Document title */
38
+ title: string;
39
+ /** Raw content */
40
+ content: string;
41
+ /** Frontmatter metadata */
42
+ frontmatter: Record<string, unknown>;
43
+ /** Extracted wiki-links [[like-this]] */
44
+ links: string[];
45
+ /** Tags extracted from content */
46
+ tags: string[];
47
+ /** Last modified timestamp */
48
+ modified: Date;
49
+ }
50
+ interface SearchResult {
51
+ /** Document that matched */
52
+ document: Document;
53
+ /** Relevance score (0-1) */
54
+ score: number;
55
+ /** Matching snippet */
56
+ snippet: string;
57
+ /** Which terms matched */
58
+ matchedTerms: string[];
59
+ }
60
+ interface SearchOptions {
61
+ /** Max results to return */
62
+ limit?: number;
63
+ /** Minimum score threshold (0-1) */
64
+ minScore?: number;
65
+ /** Filter by category */
66
+ category?: string;
67
+ /** Filter by tags */
68
+ tags?: string[];
69
+ /** Include full content in results */
70
+ fullContent?: boolean;
71
+ /** Boost recent documents in ranking */
72
+ temporalBoost?: boolean;
73
+ /**
74
+ * v2.7 — Enable chunk-level BM25 pre-filtering before semantic search.
75
+ * Chunks documents into ~600-char sentence windows and ranks chunks by
76
+ * keyword overlap so that relevant content deep in long documents isn't
77
+ * silently dropped by fixed-N embedding limits.
78
+ */
79
+ chunkPrefilter?: boolean;
80
+ /**
81
+ * v2.7 — Exhaustive threshold-based retrieval for aggregation queries.
82
+ * Instead of a fixed top_k, keeps pulling results until the normalised
83
+ * relevance score drops below this threshold (0-1). Set to e.g. 0.01
84
+ * for aggregation / "list all" queries. Overrides `limit` when set.
85
+ */
86
+ relevanceThreshold?: number;
87
+ /**
88
+ * v2.7 — Maximum results when using relevanceThreshold.
89
+ * Prevents runaway result sets. Default 40.
90
+ */
91
+ thresholdMaxResults?: number;
92
+ }
93
+ /**
94
+ * v2.7 — A date reference extracted from document content at ingest time.
95
+ */
96
+ interface ExtractedDate {
97
+ /** ISO date string (YYYY-MM-DD) or "duration:<value>" */
98
+ date: string;
99
+ /** Surrounding context snippet (~150 chars) */
100
+ context: string;
101
+ /** Document id the date was extracted from */
102
+ documentId: string;
103
+ }
104
+ /**
105
+ * v2.7 — An extracted user preference from conversation content.
106
+ */
107
+ interface ExtractedPreference {
108
+ /** The preference category (tool, hobby, brand, etc.) */
109
+ category: string;
110
+ /** The preference value */
111
+ value: string;
112
+ /** Document id it was extracted from */
113
+ documentId: string;
114
+ /** Surrounding context snippet */
115
+ context: string;
116
+ }
117
+ interface StoreOptions {
118
+ /** Category to store in */
119
+ category: string;
120
+ /** Document title (used for filename) */
121
+ title: string;
122
+ /** Content body */
123
+ content: string;
124
+ /** Frontmatter metadata */
125
+ frontmatter?: Record<string, unknown>;
126
+ /** Override existing file */
127
+ overwrite?: boolean;
128
+ /** Trigger qmd update after storing */
129
+ qmdUpdate?: boolean;
130
+ /** Trigger qmd embed after storing (implies qmdUpdate) */
131
+ qmdEmbed?: boolean;
132
+ /** Optional qmd index name override (defaults to configured/global index) */
133
+ qmdIndexName?: string;
134
+ }
135
+ interface SyncOptions {
136
+ /** Target directory to sync to */
137
+ target: string;
138
+ /** Delete files in target not in source */
139
+ deleteOrphans?: boolean;
140
+ /** Dry run - don't actually sync */
141
+ dryRun?: boolean;
142
+ }
143
+ interface SyncResult {
144
+ copied: string[];
145
+ deleted: string[];
146
+ unchanged: string[];
147
+ errors: string[];
148
+ }
149
+ type Category = 'preferences' | 'decisions' | 'rules' | 'patterns' | 'people' | 'projects' | 'goals' | 'transcripts' | 'inbox' | 'templates' | 'facts' | 'feelings' | 'lessons' | 'commitments' | 'handoffs' | string;
150
+ declare const DEFAULT_CATEGORIES: Category[];
151
+ /**
152
+ * Memory Type Taxonomy (Benthic's 8 categories)
153
+ * Knowing WHAT KIND of thing helps you know WHERE to put it
154
+ */
155
+ type MemoryType = 'fact' | 'feeling' | 'decision' | 'lesson' | 'commitment' | 'preference' | 'relationship' | 'project';
156
+ declare const MEMORY_TYPES: MemoryType[];
157
+ /**
158
+ * Memory type to category mapping
159
+ */
160
+ declare const TYPE_TO_CATEGORY: Record<MemoryType, Category>;
161
+ /**
162
+ * Handoff document - bridges sessions
163
+ */
164
+ interface HandoffDocument {
165
+ /** When this handoff was created */
166
+ created: string;
167
+ /** Session key or identifier */
168
+ sessionKey?: string;
169
+ /** What I was working on */
170
+ workingOn: string[];
171
+ /** What is currently blocked */
172
+ blocked: string[];
173
+ /** What comes next */
174
+ nextSteps: string[];
175
+ /** Emotional state/energy */
176
+ feeling?: string;
177
+ /** Key decisions made */
178
+ decisions?: string[];
179
+ /** Open questions */
180
+ openQuestions?: string[];
181
+ }
182
+ /**
183
+ * Session recap - who I was when I woke up
184
+ */
185
+ interface SessionRecap {
186
+ /** When recap was generated */
187
+ generated: string;
188
+ /** Recent handoffs (last N) */
189
+ recentHandoffs: HandoffDocument[];
190
+ /** Active projects */
191
+ activeProjects: string[];
192
+ /** Pending commitments */
193
+ pendingCommitments: string[];
194
+ /** Recent decisions made */
195
+ recentDecisions?: string[];
196
+ /** Recent lessons learned */
197
+ recentLessons: string[];
198
+ /** Key relationships to remember */
199
+ keyRelationships: string[];
200
+ /** Current emotional arc */
201
+ emotionalArc?: string;
202
+ }
203
+ declare const DEFAULT_CONFIG: Partial<VaultConfig>;
204
+
205
+ export { type Category as C, type Document as D, type ExtractedDate as E, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e, type ExtractedPreference as f, DEFAULT_CATEGORIES as g, DEFAULT_CONFIG as h, MEMORY_TYPES as i, type VaultMeta as j };
@@ -21,7 +21,7 @@ const MAX_CONTEXT_PROMPT_LENGTH = 500;
21
21
  const MAX_CONTEXT_SNIPPET_LENGTH = 220;
22
22
  const MAX_RECAP_RESULTS = 6;
23
23
  const MAX_RECAP_SNIPPET_LENGTH = 220;
24
- const EVENT_NAME_SEPARATOR_RE = /[.:/]/g;
24
+ const EVENT_NAME_SEPARATOR_RE = /[._:\/-]+/g;
25
25
  const OBSERVE_CURSOR_FILE = 'observe-cursors.json';
26
26
  const ONE_KIB = 1024;
27
27
  const ONE_MIB = ONE_KIB * ONE_KIB;
@@ -178,7 +178,7 @@ function shouldObserveActiveSessions(vaultPath, agentId) {
178
178
  const sessionId = typeof value.sessionId === 'string' ? value.sessionId.trim() : '';
179
179
  if (!/^[a-zA-Z0-9._-]{1,200}$/.test(sessionId)) continue;
180
180
 
181
- const filePath = path.join(sessionsDir, `${sessionId}.jsonl`);
181
+ let filePath = path.join(sessionsDir, `${sessionId}.jsonl`);
182
182
  let stat;
183
183
  try {
184
184
  stat = fs.statSync(filePath);
@@ -187,6 +187,27 @@ function shouldObserveActiveSessions(vaultPath, agentId) {
187
187
  }
188
188
  if (!stat.isFile()) continue;
189
189
 
190
+ // After /new or /reset, the main .jsonl is emptied — fall back to reset file
191
+ if (stat.size < 100) {
192
+ const resetPrefix = `${sessionId}.jsonl.reset.`;
193
+ try {
194
+ const resetFiles = fs.readdirSync(sessionsDir)
195
+ .filter(f => f.startsWith(resetPrefix))
196
+ .sort()
197
+ .reverse();
198
+ if (resetFiles.length > 0) {
199
+ const resetPath = path.join(sessionsDir, resetFiles[0]);
200
+ const resetStat = fs.statSync(resetPath);
201
+ if (resetStat.isFile() && resetStat.size > stat.size) {
202
+ filePath = resetPath;
203
+ stat = resetStat;
204
+ }
205
+ }
206
+ } catch {
207
+ // Ignore — use original file
208
+ }
209
+ }
210
+
190
211
  const fileSize = stat.size;
191
212
  const cursorEntry = cursors[sessionId];
192
213
  const previousOffset = Number.isFinite(cursorEntry?.lastObservedOffset)
@@ -366,16 +387,28 @@ function normalizeEventToken(value) {
366
387
  .trim()
367
388
  .toLowerCase()
368
389
  .replace(/\s+/g, '')
369
- .replace(EVENT_NAME_SEPARATOR_RE, ':');
390
+ .replace(EVENT_NAME_SEPARATOR_RE, ':')
391
+ .replace(/^:+|:+$/g, '');
392
+ }
393
+
394
+ function collapseEventToken(value) {
395
+ return normalizeEventToken(value).replace(/:/g, '');
370
396
  }
371
397
 
372
398
  function eventMatches(event, type, action) {
373
- const normalizedExpected = `${normalizeEventToken(type)}:${normalizeEventToken(action)}`;
399
+ const normalizedExpected = [normalizeEventToken(type), normalizeEventToken(action)]
400
+ .filter(Boolean)
401
+ .join(':');
402
+ const collapsedExpected = collapseEventToken(normalizedExpected);
374
403
  const normalizedType = normalizeEventToken(event?.type);
375
404
  const normalizedAction = normalizeEventToken(event?.action);
376
405
 
377
406
  if (normalizedType && normalizedAction) {
378
- if (`${normalizedType}:${normalizedAction}` === normalizedExpected) {
407
+ const normalizedEventPair = `${normalizedType}:${normalizedAction}`;
408
+ if (
409
+ normalizedEventPair === normalizedExpected
410
+ || collapseEventToken(normalizedEventPair) === collapsedExpected
411
+ ) {
379
412
  return true;
380
413
  }
381
414
  }
@@ -391,7 +424,10 @@ function eventMatches(event, type, action) {
391
424
  for (const alias of aliases) {
392
425
  const normalizedAlias = normalizeEventToken(alias);
393
426
  if (!normalizedAlias) continue;
394
- if (normalizedAlias === normalizedExpected) {
427
+ if (
428
+ normalizedAlias === normalizedExpected
429
+ || collapseEventToken(normalizedAlias) === collapsedExpected
430
+ ) {
395
431
  return true;
396
432
  }
397
433
  }
@@ -402,6 +438,7 @@ function eventMatches(event, type, action) {
402
438
  function eventIncludesToken(event, token) {
403
439
  const normalizedToken = normalizeEventToken(token);
404
440
  if (!normalizedToken) return false;
441
+ const collapsedToken = collapseEventToken(normalizedToken);
405
442
 
406
443
  const values = [
407
444
  event?.type,
@@ -416,7 +453,12 @@ function eventIncludesToken(event, token) {
416
453
  return values
417
454
  .map((value) => normalizeEventToken(value))
418
455
  .filter(Boolean)
419
- .some((value) => value.includes(normalizedToken));
456
+ .some((value) => {
457
+ if (value.includes(normalizedToken)) {
458
+ return true;
459
+ }
460
+ return collapseEventToken(value).includes(collapsedToken);
461
+ });
420
462
  }
421
463
 
422
464
  // Validate vault path - must be absolute and exist
@@ -450,6 +492,14 @@ function findVaultPath() {
450
492
  if (process.env.CLAWVAULT_PATH) {
451
493
  return validateVaultPath(process.env.CLAWVAULT_PATH);
452
494
  }
495
+ const configuredCandidates = [
496
+ process.env.OPENCLAW_MEMORY_PATH,
497
+ process.env.OPENCLAW_VAULT_PATH
498
+ ];
499
+ for (const candidate of configuredCandidates) {
500
+ const validated = validateVaultPath(candidate);
501
+ if (validated) return validated;
502
+ }
453
503
 
454
504
  // Walk up from cwd
455
505
  let dir = process.cwd();
@@ -466,6 +516,19 @@ function findVaultPath() {
466
516
 
467
517
  dir = path.dirname(dir);
468
518
  }
519
+
520
+ // Canonical local-first defaults for OpenClaw users.
521
+ const homeDir = normalizeAbsoluteEnvPath(process.env.HOME) || os.homedir();
522
+ const homeCandidates = [
523
+ path.join(homeDir, 'memory'),
524
+ path.join(homeDir, 'Memory'),
525
+ path.join(homeDir, 'vault'),
526
+ path.join(homeDir, 'Vault')
527
+ ];
528
+ for (const candidate of homeCandidates) {
529
+ const validated = validateVaultPath(candidate);
530
+ if (validated) return validated;
531
+ }
469
532
 
470
533
  return null;
471
534
  }
@@ -46,6 +46,8 @@ async function loadHandler() {
46
46
  afterEach(() => {
47
47
  vi.clearAllMocks();
48
48
  delete process.env.CLAWVAULT_PATH;
49
+ delete process.env.OPENCLAW_MEMORY_PATH;
50
+ delete process.env.OPENCLAW_VAULT_PATH;
49
51
  delete process.env.OPENCLAW_STATE_DIR;
50
52
  delete process.env.OPENCLAW_HOME;
51
53
  delete process.env.OPENCLAW_AGENT_ID;
@@ -105,6 +107,28 @@ describe('clawvault hook handler', () => {
105
107
  fs.rmSync(vaultPath, { recursive: true, force: true });
106
108
  });
107
109
 
110
+ it('supports slash-prefixed command actions for /new', async () => {
111
+ const vaultPath = makeVaultFixture();
112
+ process.env.CLAWVAULT_PATH = vaultPath;
113
+ execFileSyncMock.mockReturnValue('');
114
+
115
+ const handler = await loadHandler();
116
+ await handler({
117
+ type: 'command',
118
+ action: '/new',
119
+ sessionKey: 'agent:clawdious:main',
120
+ context: { commandSource: 'slash' }
121
+ });
122
+
123
+ expect(execFileSyncMock).toHaveBeenCalledWith(
124
+ 'clawvault',
125
+ expect.arrayContaining(['checkpoint', '--working-on']),
126
+ expect.objectContaining({ shell: false })
127
+ );
128
+
129
+ fs.rmSync(vaultPath, { recursive: true, force: true });
130
+ });
131
+
108
132
  it('injects recap and memory context on session start alias event', async () => {
109
133
  const vaultPath = makeVaultFixture();
110
134
  process.env.CLAWVAULT_PATH = vaultPath;
@@ -241,6 +265,73 @@ describe('clawvault hook handler', () => {
241
265
  fs.rmSync(vaultPath, { recursive: true, force: true });
242
266
  });
243
267
 
268
+ it('supports compaction action separator variants', async () => {
269
+ const vaultPath = makeVaultFixture();
270
+ process.env.CLAWVAULT_PATH = vaultPath;
271
+ execFileSyncMock.mockReturnValue('');
272
+
273
+ const handler = await loadHandler();
274
+ await handler({
275
+ type: 'compaction',
276
+ action: 'memory_flush',
277
+ sessionKey: 'agent:clawdious:main'
278
+ });
279
+
280
+ expect(execFileSyncMock).toHaveBeenCalledWith(
281
+ 'clawvault',
282
+ expect.arrayContaining(['observe', '--cron', '--min-new', '1']),
283
+ expect.objectContaining({ shell: false })
284
+ );
285
+
286
+ fs.rmSync(vaultPath, { recursive: true, force: true });
287
+ });
288
+
289
+ it('discovers canonical ~/memory vault when env and cwd do not provide one', async () => {
290
+ const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), 'clawvault-home-'));
291
+ const vaultPath = path.join(fakeHome, 'memory');
292
+ fs.mkdirSync(vaultPath, { recursive: true });
293
+ fs.writeFileSync(path.join(vaultPath, '.clawvault.json'), JSON.stringify({ name: 'home' }), 'utf-8');
294
+ const originalHome = process.env.HOME;
295
+ const originalClawvaultPath = process.env.CLAWVAULT_PATH;
296
+ const originalOpenclawMemory = process.env.OPENCLAW_MEMORY_PATH;
297
+ const originalOpenclawVault = process.env.OPENCLAW_VAULT_PATH;
298
+ process.env.HOME = fakeHome;
299
+ delete process.env.CLAWVAULT_PATH;
300
+ delete process.env.OPENCLAW_MEMORY_PATH;
301
+ delete process.env.OPENCLAW_VAULT_PATH;
302
+ // Mock cwd to a temp dir without a vault so walk-up doesn't find one
303
+ const fakeCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'clawvault-cwd-'));
304
+ const originalCwd = process.cwd;
305
+ process.cwd = () => fakeCwd;
306
+ try {
307
+ execFileSyncMock.mockReturnValue('');
308
+
309
+ const handler = await loadHandler();
310
+ await handler({
311
+ eventName: 'compaction:memoryFlush',
312
+ sessionKey: 'agent:main:main'
313
+ });
314
+
315
+ expect(execFileSyncMock).toHaveBeenCalledWith(
316
+ 'clawvault',
317
+ expect.arrayContaining(['observe', '--cron', '-v', vaultPath]),
318
+ expect.objectContaining({ shell: false })
319
+ );
320
+ } finally {
321
+ if (originalHome === undefined) {
322
+ delete process.env.HOME;
323
+ } else {
324
+ process.env.HOME = originalHome;
325
+ }
326
+ if (originalClawvaultPath !== undefined) process.env.CLAWVAULT_PATH = originalClawvaultPath;
327
+ if (originalOpenclawMemory !== undefined) process.env.OPENCLAW_MEMORY_PATH = originalOpenclawMemory;
328
+ if (originalOpenclawVault !== undefined) process.env.OPENCLAW_VAULT_PATH = originalOpenclawVault;
329
+ process.cwd = originalCwd;
330
+ fs.rmSync(fakeHome, { recursive: true, force: true });
331
+ fs.rmSync(fakeCwd, { recursive: true, force: true });
332
+ }
333
+ });
334
+
244
335
  it('runs weekly reflection on cron.weekly at Sunday midnight', async () => {
245
336
  const vaultPath = makeVaultFixture();
246
337
  process.env.CLAWVAULT_PATH = vaultPath;