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,36 @@
1
+ import { TemplateRegistry } from './templates.cjs';
2
+ export { classifyText, getAllSchemas, getSchema, getSchemaNames, initializeTemplateRegistry } from './templates.cjs';
3
+ export { detectCategory, extractObservations, extractSearchTerms, isObservable, processMessageForObservations } from './observe.cjs';
4
+ export { buildFullContext, buildPreferenceContext, buildSessionRecap, formatMemoriesForContext, formatSearchResults, scanVaultFiles } from './inject.cjs';
5
+ export { appendToLedger, batchWriteObservations, ensureVaultStructure, writeObservation, writeVaultFile } from './vault.cjs';
6
+
7
+ /**
8
+ * ClawVault OpenClaw Plugin v2.2.0
9
+ *
10
+ * Memory slot provider for OpenClaw. Template-driven observational memory architecture:
11
+ * memories are captured automatically from conversations, classified against template
12
+ * schemas, and stored with proper frontmatter validation.
13
+ *
14
+ * Architecture:
15
+ * ClawVault (engine) ←→ Plugin (integration) ←→ OpenClaw (agent platform)
16
+ * - ClawVault = vault, observations, search index, knowledge graph
17
+ * - Plugin = auto-recall, auto-capture, search tools, lifecycle hooks
18
+ * - OpenClaw = agent runtime, sessions, tools, channels
19
+ * - Templates = schema definitions for primitive types
20
+ *
21
+ * The plugin does NOT give the agent a "store memory" tool. Memory is
22
+ * observational: the system watches conversations and captures automatically.
23
+ * The agent searches memory; it doesn't manage it.
24
+ */
25
+
26
+ declare function getTemplateRegistry(): TemplateRegistry | null;
27
+ declare const clawvaultPlugin: {
28
+ id: string;
29
+ name: string;
30
+ description: string;
31
+ version: string;
32
+ kind: "memory";
33
+ register(api: any): void;
34
+ };
35
+
36
+ export { clawvaultPlugin as default, getTemplateRegistry };
@@ -0,0 +1,36 @@
1
+ import { TemplateRegistry } from './templates.js';
2
+ export { classifyText, getAllSchemas, getSchema, getSchemaNames, initializeTemplateRegistry } from './templates.js';
3
+ export { detectCategory, extractObservations, extractSearchTerms, isObservable, processMessageForObservations } from './observe.js';
4
+ export { buildFullContext, buildPreferenceContext, buildSessionRecap, formatMemoriesForContext, formatSearchResults, scanVaultFiles } from './inject.js';
5
+ export { appendToLedger, batchWriteObservations, ensureVaultStructure, writeObservation, writeVaultFile } from './vault.js';
6
+
7
+ /**
8
+ * ClawVault OpenClaw Plugin v2.2.0
9
+ *
10
+ * Memory slot provider for OpenClaw. Template-driven observational memory architecture:
11
+ * memories are captured automatically from conversations, classified against template
12
+ * schemas, and stored with proper frontmatter validation.
13
+ *
14
+ * Architecture:
15
+ * ClawVault (engine) ←→ Plugin (integration) ←→ OpenClaw (agent platform)
16
+ * - ClawVault = vault, observations, search index, knowledge graph
17
+ * - Plugin = auto-recall, auto-capture, search tools, lifecycle hooks
18
+ * - OpenClaw = agent runtime, sessions, tools, channels
19
+ * - Templates = schema definitions for primitive types
20
+ *
21
+ * The plugin does NOT give the agent a "store memory" tool. Memory is
22
+ * observational: the system watches conversations and captures automatically.
23
+ * The agent searches memory; it doesn't manage it.
24
+ */
25
+
26
+ declare function getTemplateRegistry(): TemplateRegistry | null;
27
+ declare const clawvaultPlugin: {
28
+ id: string;
29
+ name: string;
30
+ description: string;
31
+ version: string;
32
+ kind: "memory";
33
+ register(api: any): void;
34
+ };
35
+
36
+ export { clawvaultPlugin as default, getTemplateRegistry };
@@ -0,0 +1,572 @@
1
+ import {
2
+ appendToLedger,
3
+ batchWriteObservations,
4
+ ensureVaultStructure,
5
+ writeObservation,
6
+ writeVaultFile
7
+ } from "../chunk-MFM6K7PU.js";
8
+ import {
9
+ buildFullContext,
10
+ buildPreferenceContext,
11
+ buildSessionRecap,
12
+ formatMemoriesForContext,
13
+ formatSearchResults,
14
+ scanVaultFiles
15
+ } from "../chunk-CMB7UL7C.js";
16
+ import {
17
+ detectCategory,
18
+ extractObservations,
19
+ extractSearchTerms,
20
+ isObservable,
21
+ processMessageForObservations
22
+ } from "../chunk-6U6MK36V.js";
23
+ import {
24
+ classifyText,
25
+ getAllSchemas,
26
+ getSchema,
27
+ getSchemaNames,
28
+ initializeTemplateRegistry
29
+ } from "../chunk-GQSLDZTS.js";
30
+ import {
31
+ __require
32
+ } from "../chunk-3RG5ZIWI.js";
33
+
34
+ // src/plugin/index.ts
35
+ import { execFileSync, execFile } from "child_process";
36
+ import { existsSync, readFileSync, mkdirSync } from "fs";
37
+ import { join, basename } from "path";
38
+ import { Type } from "@sinclair/typebox";
39
+ function resolveVaultPath(cfg) {
40
+ if (cfg?.vaultPath) return cfg.vaultPath;
41
+ if (process.env.CLAWVAULT_PATH) return process.env.CLAWVAULT_PATH;
42
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
43
+ for (const candidate of [`${home}/clawvault`, `${home}/.clawvault`]) {
44
+ if (existsSync(join(candidate, ".clawvault.json"))) return candidate;
45
+ }
46
+ return `${home}/.clawvault`;
47
+ }
48
+ function getVaultConfig(vaultPath) {
49
+ const configPath = join(vaultPath, ".clawvault.json");
50
+ if (!existsSync(configPath)) return null;
51
+ try {
52
+ return JSON.parse(readFileSync(configPath, "utf-8"));
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+ function qmdHybridSearch(query, collection, limit = 10) {
58
+ const sanitized = query.replace(/['']/g, " ").replace(/[^\w\s\-.,?!]/g, " ").trim();
59
+ if (!sanitized) return [];
60
+ try {
61
+ const result = execFileSync("qmd", [
62
+ "query",
63
+ sanitized,
64
+ "-n",
65
+ String(limit),
66
+ "--json",
67
+ "-c",
68
+ collection
69
+ ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 10 * 1024 * 1024, timeout: 3e4 });
70
+ const parsed = JSON.parse(result);
71
+ if (Array.isArray(parsed) && parsed.length > 0) return parsed;
72
+ } catch (err) {
73
+ if (err?.stdout) {
74
+ try {
75
+ const parsed = JSON.parse(err.stdout);
76
+ if (Array.isArray(parsed) && parsed.length > 0) return parsed;
77
+ } catch {
78
+ }
79
+ }
80
+ }
81
+ try {
82
+ const result = execFileSync("qmd", [
83
+ "search",
84
+ sanitized,
85
+ "-n",
86
+ String(limit),
87
+ "--json",
88
+ "-c",
89
+ collection
90
+ ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 10 * 1024 * 1024, timeout: 15e3 });
91
+ return JSON.parse(result);
92
+ } catch (err) {
93
+ if (err?.stdout) {
94
+ try {
95
+ return JSON.parse(err.stdout);
96
+ } catch {
97
+ }
98
+ }
99
+ return [];
100
+ }
101
+ }
102
+ function observe(vaultPath, content, meta = {}) {
103
+ try {
104
+ const args = ["observe", "--content", content];
105
+ if (meta.tags?.length) args.push("--tags", meta.tags.join(","));
106
+ execFile("clawvault", args, { cwd: vaultPath, timeout: 15e3 }, () => {
107
+ });
108
+ } catch {
109
+ }
110
+ }
111
+ function qmdUpdateAsync(collection) {
112
+ try {
113
+ execFile("qmd", ["update", "-c", collection], { timeout: 3e4 }, () => {
114
+ });
115
+ execFile("qmd", ["embed", "-c", collection], { timeout: 6e4 }, () => {
116
+ });
117
+ } catch {
118
+ }
119
+ }
120
+ var templateRegistry = null;
121
+ function getTemplateRegistry() {
122
+ return templateRegistry;
123
+ }
124
+ var clawvaultPlugin = {
125
+ id: "clawvault",
126
+ name: "ClawVault Memory",
127
+ description: "Template-driven observational memory with hybrid search. Memories are captured automatically from conversations and classified against template schemas.",
128
+ version: "2.2.0",
129
+ kind: "memory",
130
+ register(api) {
131
+ const vaultPath = resolveVaultPath(api.pluginConfig);
132
+ const collection = api.pluginConfig?.collection || "clawvault";
133
+ const autoRecall = api.pluginConfig?.autoRecall !== false;
134
+ const autoCapture = api.pluginConfig?.autoCapture !== false;
135
+ const recallLimit = api.pluginConfig?.recallLimit || 5;
136
+ const templatesDir = api.pluginConfig?.templatesDir ?? join(vaultPath, "..", "..", "templates");
137
+ templateRegistry = initializeTemplateRegistry(templatesDir);
138
+ api.logger.info(`[clawvault] Template registry initialized with ${templateRegistry.schemas.size} schemas`);
139
+ if (!existsSync(join(vaultPath, ".clawvault.json"))) {
140
+ api.logger.warn(`[clawvault] Vault not found at ${vaultPath}`);
141
+ return;
142
+ }
143
+ ensureVaultStructure(vaultPath);
144
+ api.logger.info(`[clawvault] v2.2.0 vault=${vaultPath} collection=${collection} recall=${autoRecall} capture=${autoCapture}`);
145
+ api.registerTool({
146
+ name: "memory_search",
147
+ label: "Memory Search",
148
+ description: "Search through long-term memories using ClawVault. Supports preferences, temporal queries, and multi-session knowledge retrieval.",
149
+ parameters: Type.Object({
150
+ query: Type.String({ description: "Search query \u2014 natural language question or keyword search" }),
151
+ limit: Type.Optional(Type.Number({ description: "Max results (default: 10)" })),
152
+ queryType: Type.Optional(Type.Union([
153
+ Type.Literal("preference"),
154
+ Type.Literal("temporal"),
155
+ Type.Literal("knowledge"),
156
+ Type.Literal("general")
157
+ ], { description: "Force query type (auto-detected if omitted)" }))
158
+ }),
159
+ async execute(_id, params) {
160
+ try {
161
+ let searchQuery = params.query;
162
+ if (params.queryType === "preference") searchQuery = `preference: ${searchQuery}`;
163
+ else if (params.queryType === "temporal") searchQuery = `when: ${searchQuery}`;
164
+ const limit = params.limit || 10;
165
+ const results = qmdHybridSearch(searchQuery, collection, limit);
166
+ if (results.length === 0) {
167
+ return {
168
+ content: [{ type: "text", text: "No relevant memories found." }],
169
+ details: { count: 0, provider: "clawvault" }
170
+ };
171
+ }
172
+ return {
173
+ content: [{ type: "text", text: formatSearchResults(results, collection) }],
174
+ details: { count: results.length, provider: "clawvault" }
175
+ };
176
+ } catch (err) {
177
+ return {
178
+ content: [{ type: "text", text: `Memory search error: ${String(err)}` }],
179
+ isError: true
180
+ };
181
+ }
182
+ }
183
+ });
184
+ api.registerTool({
185
+ name: "memory_get",
186
+ label: "Memory Get",
187
+ description: "Get vault status or stored preferences.",
188
+ parameters: Type.Object({
189
+ action: Type.Union([
190
+ Type.Literal("status"),
191
+ Type.Literal("preferences")
192
+ ], { description: "What to retrieve" })
193
+ }),
194
+ async execute(_id, params) {
195
+ try {
196
+ if (params.action === "status") {
197
+ const config = getVaultConfig(vaultPath);
198
+ let docCount = 0;
199
+ let vectorCount = 0;
200
+ try {
201
+ const stats = execFileSync("qmd", ["status", "--json", "-c", collection], {
202
+ encoding: "utf-8",
203
+ timeout: 5e3,
204
+ stdio: ["ignore", "pipe", "pipe"]
205
+ });
206
+ const parsed = JSON.parse(stats);
207
+ docCount = parsed.documents ?? parsed.doc_count ?? 0;
208
+ vectorCount = parsed.vectors ?? parsed.vector_count ?? 0;
209
+ } catch {
210
+ }
211
+ return {
212
+ content: [{ type: "text", text: JSON.stringify({
213
+ vault: vaultPath,
214
+ name: config?.name || "clawvault",
215
+ collection,
216
+ documents: docCount,
217
+ vectors: vectorCount,
218
+ autoRecall,
219
+ autoCapture,
220
+ version: "2.2.0",
221
+ templateSchemas: templateRegistry?.schemas.size ?? 0
222
+ }, null, 2) }]
223
+ };
224
+ }
225
+ const prefContext = buildPreferenceContext(vaultPath, { limit: 20 });
226
+ if (prefContext.preferenceCount === 0) {
227
+ const results = qmdHybridSearch("user preference likes dislikes prefers wants", collection, 20);
228
+ const prefResults = results.filter(
229
+ (r) => r.file?.includes("preference") || r.snippet?.toLowerCase().match(/prefer|like|want|hate|love|always|never/)
230
+ );
231
+ if (prefResults.length === 0) {
232
+ return { content: [{ type: "text", text: "No preferences found in vault." }] };
233
+ }
234
+ const text = prefResults.map((r, i) => {
235
+ const file = (r.file || "").replace(`qmd://${collection}/`, "");
236
+ const snippet = (r.snippet || "").replace(/@@ .+? @@\s*\(.+?\)\n?/g, "").trim() || r.title;
237
+ return `${i + 1}. [${file}] ${snippet}`;
238
+ }).join("\n");
239
+ return { content: [{ type: "text", text }] };
240
+ }
241
+ return { content: [{ type: "text", text: prefContext.xml }] };
242
+ } catch (err) {
243
+ return {
244
+ content: [{ type: "text", text: `Memory get error: ${String(err)}` }],
245
+ isError: true
246
+ };
247
+ }
248
+ }
249
+ });
250
+ api.registerTool({
251
+ name: "memory_store",
252
+ label: "Memory Store",
253
+ description: "Save important information in long-term memory. Use for preferences, facts, decisions, or anything worth remembering.",
254
+ parameters: Type.Object({
255
+ text: Type.String({ description: "Information to remember" }),
256
+ category: Type.Optional(Type.Union([
257
+ Type.Literal("preference"),
258
+ Type.Literal("fact"),
259
+ Type.Literal("decision"),
260
+ Type.Literal("entity"),
261
+ Type.Literal("event"),
262
+ Type.Literal("other")
263
+ ], { description: "Memory category (auto-detected if omitted)" })),
264
+ tags: Type.Optional(Type.Array(Type.String(), { description: "Tags for organization" }))
265
+ }),
266
+ async execute(_id, params) {
267
+ try {
268
+ const classification = classifyText(params.text);
269
+ const category = params.category || detectCategory(params.text);
270
+ const tags = params.tags || [category, ...classification.matchedKeywords.slice(0, 3)];
271
+ const result = writeVaultFile(vaultPath, {
272
+ primitiveType: classification.primitiveType,
273
+ title: params.text.slice(0, 80),
274
+ content: params.text,
275
+ extraFields: {
276
+ type: category,
277
+ confidence: classification.confidence,
278
+ tags
279
+ },
280
+ source: "openclaw"
281
+ });
282
+ appendToLedger(vaultPath, {
283
+ timestamp: /* @__PURE__ */ new Date(),
284
+ category,
285
+ content: params.text,
286
+ primitiveType: classification.primitiveType,
287
+ tags
288
+ });
289
+ qmdUpdateAsync(collection);
290
+ return {
291
+ content: [{ type: "text", text: `Stored: "${params.text.slice(0, 100)}${params.text.length > 100 ? "..." : ""}" [${classification.primitiveType}/${category}]` }],
292
+ details: {
293
+ action: result.created ? "created" : "updated",
294
+ category,
295
+ primitiveType: classification.primitiveType,
296
+ path: result.path
297
+ }
298
+ };
299
+ } catch (err) {
300
+ return {
301
+ content: [{ type: "text", text: `Memory store error: ${String(err)}` }],
302
+ isError: true
303
+ };
304
+ }
305
+ }
306
+ });
307
+ api.registerTool({
308
+ name: "memory_forget",
309
+ label: "Memory Forget",
310
+ description: "Delete specific memories from the vault.",
311
+ parameters: Type.Object({
312
+ query: Type.String({ description: "Search query to find the memory to delete" }),
313
+ confirm: Type.Optional(Type.Boolean({ description: "Set true to confirm deletion of first match" }))
314
+ }),
315
+ async execute(_id, params) {
316
+ try {
317
+ const results = qmdHybridSearch(params.query, collection, 5);
318
+ if (results.length === 0) {
319
+ return {
320
+ content: [{ type: "text", text: "No matching memories found." }],
321
+ details: { found: 0 }
322
+ };
323
+ }
324
+ if (!params.confirm) {
325
+ const list = results.map((r, i) => {
326
+ const file2 = (r.file || "").replace(`qmd://${collection}/`, "");
327
+ const snippet = (r.snippet || "").replace(/@@ .+? @@\s*\(.+?\)\n?/g, "").trim().slice(0, 80);
328
+ return `${i + 1}. [${file2}] ${snippet}`;
329
+ }).join("\n");
330
+ return {
331
+ content: [{ type: "text", text: `Found ${results.length} candidates:
332
+ ${list}
333
+
334
+ Call again with confirm=true to delete the top match.` }],
335
+ details: { action: "candidates", count: results.length }
336
+ };
337
+ }
338
+ const target = results[0];
339
+ const file = (target.file || "").replace(`qmd://${collection}/`, "");
340
+ const fullPath = join(vaultPath, file);
341
+ if (existsSync(fullPath)) {
342
+ const trashDir = join(vaultPath, ".trash");
343
+ if (!existsSync(trashDir)) mkdirSync(trashDir, { recursive: true });
344
+ const trashPath = join(trashDir, `${Date.now()}-${basename(file)}`);
345
+ const { renameSync } = __require("fs");
346
+ renameSync(fullPath, trashPath);
347
+ qmdUpdateAsync(collection);
348
+ return {
349
+ content: [{ type: "text", text: `Forgotten: [${file}] (moved to .trash)` }],
350
+ details: { action: "deleted", file, trashPath }
351
+ };
352
+ }
353
+ return {
354
+ content: [{ type: "text", text: `File not found on disk: ${file}` }],
355
+ details: { action: "not_found", file }
356
+ };
357
+ } catch (err) {
358
+ return {
359
+ content: [{ type: "text", text: `Memory forget error: ${String(err)}` }],
360
+ isError: true
361
+ };
362
+ }
363
+ }
364
+ });
365
+ if (autoRecall) {
366
+ api.on("before_agent_start", async (event) => {
367
+ if (!event.prompt || event.prompt.length < 10) return;
368
+ if (event.prompt.includes("HEARTBEAT") || event.prompt.startsWith("[System")) return;
369
+ try {
370
+ const contextParts = [];
371
+ const recap = buildSessionRecap(vaultPath, {
372
+ maxAge: 24 * 60 * 60 * 1e3,
373
+ // 24 hours
374
+ limit: 10,
375
+ includeContent: true
376
+ });
377
+ if (recap.xml) {
378
+ contextParts.push(recap.xml);
379
+ }
380
+ const searchTerms = extractSearchTerms(event.prompt);
381
+ const results = qmdHybridSearch(searchTerms, collection, recallLimit);
382
+ if (results.length > 0) {
383
+ const topScore = results[0]?.score ?? 0;
384
+ if (topScore >= 0.25) {
385
+ contextParts.push(formatMemoriesForContext(results, collection));
386
+ api.logger.info(`[clawvault] auto-recall: ${results.length} memories (top: ${(topScore * 100).toFixed(0)}%, query: "${searchTerms.slice(0, 60)}")`);
387
+ }
388
+ }
389
+ if (contextParts.length === 0) return;
390
+ return {
391
+ prependContext: contextParts.join("\n\n")
392
+ };
393
+ } catch (err) {
394
+ api.logger.warn(`[clawvault] auto-recall failed: ${String(err)}`);
395
+ }
396
+ }, { priority: 10 });
397
+ }
398
+ if (autoCapture) {
399
+ api.on("message_received", async (event) => {
400
+ if (!event.content || !isObservable(event.content)) return;
401
+ try {
402
+ const result = processMessageForObservations(event.content, {
403
+ from: event.from,
404
+ sessionId: event.sessionId
405
+ });
406
+ if (result.observations.length === 0) return;
407
+ const writeResult = batchWriteObservations(vaultPath, result.observations, {
408
+ source: "openclaw",
409
+ sessionId: event.sessionId,
410
+ actor: event.from || "user",
411
+ writeLedger: true,
412
+ writeFiles: false
413
+ // Only write to ledger for speed
414
+ });
415
+ api.logger.info(`[clawvault] auto-captured ${writeResult.successful} observations from incoming message`);
416
+ } catch (err) {
417
+ api.logger.warn(`[clawvault] message capture failed: ${String(err)}`);
418
+ }
419
+ });
420
+ api.on("agent_end", async (event) => {
421
+ if (!event.success || !event.messages?.length) return;
422
+ try {
423
+ let captured = 0;
424
+ for (const msg of event.messages) {
425
+ if (!msg || typeof msg !== "object") continue;
426
+ if (msg.role === "user") {
427
+ const content = typeof msg.content === "string" ? msg.content : Array.isArray(msg.content) ? msg.content.filter((b) => b?.type === "text").map((b) => b.text).join(" ") : "";
428
+ if (isObservable(content)) {
429
+ const result = processMessageForObservations(content);
430
+ for (const obs of result.observations) {
431
+ observe(vaultPath, obs.text, { tags: obs.tags });
432
+ captured++;
433
+ }
434
+ }
435
+ }
436
+ }
437
+ if (captured > 0) {
438
+ api.logger.info(`[clawvault] agent_end: captured ${captured} observations`);
439
+ qmdUpdateAsync(collection);
440
+ }
441
+ } catch (err) {
442
+ api.logger.warn(`[clawvault] agent_end capture failed: ${String(err)}`);
443
+ }
444
+ });
445
+ }
446
+ api.on("before_compaction", async () => {
447
+ try {
448
+ execFileSync("qmd", ["update", "-c", collection], {
449
+ timeout: 15e3,
450
+ encoding: "utf-8",
451
+ stdio: ["ignore", "pipe", "pipe"]
452
+ });
453
+ api.logger.info("[clawvault] pre-compaction index update complete");
454
+ } catch (err) {
455
+ api.logger.warn(`[clawvault] pre-compaction update failed: ${String(err)}`);
456
+ }
457
+ });
458
+ api.registerService({
459
+ id: "clawvault",
460
+ start: () => {
461
+ api.logger.info(`[clawvault] service started \u2014 vault=${vaultPath}`);
462
+ qmdUpdateAsync(collection);
463
+ },
464
+ stop: () => {
465
+ api.logger.info("[clawvault] service stopped");
466
+ }
467
+ });
468
+ api.registerCli(
469
+ ({ program }) => {
470
+ const cmd = program.command("vault").description("ClawVault memory commands");
471
+ cmd.command("status").action(() => {
472
+ const config = getVaultConfig(vaultPath);
473
+ console.log(JSON.stringify({
474
+ vault: vaultPath,
475
+ version: "2.2.0",
476
+ templateSchemas: templateRegistry?.schemas.size ?? 0,
477
+ ...config
478
+ }, null, 2));
479
+ });
480
+ cmd.command("search <query>").option("-n, --limit <n>", "Max results", "10").action((query, opts) => {
481
+ const results = qmdHybridSearch(query, collection, parseInt(opts.limit));
482
+ console.log(formatSearchResults(results, collection));
483
+ });
484
+ cmd.command("templates").action(() => {
485
+ const schemas = getAllSchemas();
486
+ console.log("Registered template schemas:");
487
+ for (const schema of schemas) {
488
+ console.log(` - ${schema.primitive}: ${schema.description || "(no description)"}`);
489
+ console.log(` Fields: ${Object.keys(schema.fields).join(", ")}`);
490
+ }
491
+ });
492
+ cmd.command("classify <text>").action((text) => {
493
+ const result = classifyText(text);
494
+ console.log(JSON.stringify(result, null, 2));
495
+ });
496
+ },
497
+ { commands: ["vault"] }
498
+ );
499
+ api.registerCommand({
500
+ name: "vault",
501
+ description: "ClawVault status and quick search",
502
+ acceptsArgs: true,
503
+ requireAuth: true,
504
+ handler: (ctx) => {
505
+ const args = (ctx.args || "").trim();
506
+ if (!args || args === "status") {
507
+ const config = getVaultConfig(vaultPath);
508
+ let docCount = 0, vectorCount = 0;
509
+ try {
510
+ const stats = execFileSync("qmd", ["status", "--json", "-c", collection], {
511
+ encoding: "utf-8",
512
+ timeout: 5e3,
513
+ stdio: ["ignore", "pipe", "pipe"]
514
+ });
515
+ const p = JSON.parse(stats);
516
+ docCount = p.documents ?? p.doc_count ?? 0;
517
+ vectorCount = p.vectors ?? p.vector_count ?? 0;
518
+ } catch {
519
+ }
520
+ return {
521
+ text: `\u{1F9E0} ClawVault v2.2.0
522
+ Vault: ${vaultPath}
523
+ Docs: ${docCount} | Vectors: ${vectorCount}
524
+ Recall: ${autoRecall ? "\u2705" : "\u274C"} | Capture: ${autoCapture ? "\u2705" : "\u274C"}
525
+ Templates: ${templateRegistry?.schemas.size ?? 0} schemas`
526
+ };
527
+ }
528
+ if (args.startsWith("search ")) {
529
+ const query = args.slice(7).trim();
530
+ const results = qmdHybridSearch(query, collection, 5);
531
+ return { text: formatSearchResults(results, collection) };
532
+ }
533
+ if (args === "templates") {
534
+ const names = getSchemaNames();
535
+ return { text: `Template schemas: ${names.join(", ")}` };
536
+ }
537
+ if (args === "recap") {
538
+ const recap = buildSessionRecap(vaultPath, { limit: 10, includeContent: true });
539
+ return { text: recap.xml || "No recent activity found." };
540
+ }
541
+ return { text: "Usage: /vault [status|search <query>|templates|recap]" };
542
+ }
543
+ });
544
+ console.log(`[clawvault] v2.2.0 registered \u2014 vault=${vaultPath} templates=${templateRegistry?.schemas.size ?? 0}`);
545
+ }
546
+ };
547
+ var plugin_default = clawvaultPlugin;
548
+ export {
549
+ appendToLedger,
550
+ batchWriteObservations,
551
+ buildFullContext,
552
+ buildPreferenceContext,
553
+ buildSessionRecap,
554
+ classifyText,
555
+ plugin_default as default,
556
+ detectCategory,
557
+ ensureVaultStructure,
558
+ extractObservations,
559
+ extractSearchTerms,
560
+ formatMemoriesForContext,
561
+ formatSearchResults,
562
+ getAllSchemas,
563
+ getSchema,
564
+ getSchemaNames,
565
+ getTemplateRegistry,
566
+ initializeTemplateRegistry,
567
+ isObservable,
568
+ processMessageForObservations,
569
+ scanVaultFiles,
570
+ writeObservation,
571
+ writeVaultFile
572
+ };