clawvault 3.4.1 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,22 @@
1
1
  import {
2
2
  buildRecallResult
3
3
  } from "./chunk-RL2L6I6K.js";
4
+ import {
5
+ recover
6
+ } from "./chunk-OIWVQYQF.js";
7
+ import {
8
+ buildSessionRecap
9
+ } from "./chunk-ZKGY7WTT.js";
10
+ import {
11
+ checkpoint,
12
+ flush
13
+ } from "./chunk-F55HGNU4.js";
4
14
  import {
5
15
  synthesizeEntityProfiles
6
16
  } from "./chunk-NSXYM6EZ.js";
17
+ import {
18
+ runReflection
19
+ } from "./chunk-TWMI3SNN.js";
7
20
  import {
8
21
  normalizeForDedup,
9
22
  similarityScore
@@ -707,7 +720,7 @@ import * as fs4 from "fs";
707
720
  import * as path4 from "path";
708
721
 
709
722
  // src/plugin/clawvault-cli.ts
710
- import { execFileSync } from "child_process";
723
+ import { execFileSync, spawn } from "child_process";
711
724
  import * as fs3 from "fs";
712
725
  import * as path3 from "path";
713
726
 
@@ -806,8 +819,6 @@ function verifyExecutableIntegrity(executablePath, expectedSha256) {
806
819
 
807
820
  // src/plugin/clawvault-cli.ts
808
821
  var MAX_CONTEXT_PROMPT_LENGTH = 500;
809
- var MAX_CONTEXT_SNIPPET_LENGTH = 220;
810
- var MAX_RECAP_SNIPPET_LENGTH = 220;
811
822
  var CLAWVAULT_EXECUTABLE = "clawvault";
812
823
  var ONE_KIB = 1024;
813
824
  var ONE_MIB = ONE_KIB * ONE_KIB;
@@ -823,139 +834,6 @@ function sanitizePromptForContext(value) {
823
834
  if (typeof value !== "string") return "";
824
835
  return value.replace(/[\x00-\x1f\x7f]/g, " ").replace(/\s+/g, " ").trim().slice(0, MAX_CONTEXT_PROMPT_LENGTH);
825
836
  }
826
- function truncateSnippet(snippet) {
827
- const safe = sanitizeForDisplay(snippet).replace(/\s+/g, " ").trim();
828
- if (safe.length <= MAX_CONTEXT_SNIPPET_LENGTH) return safe;
829
- return `${safe.slice(0, MAX_CONTEXT_SNIPPET_LENGTH - 3).trimEnd()}...`;
830
- }
831
- function truncateRecapSnippet(snippet) {
832
- const safe = sanitizeForDisplay(snippet).replace(/\s+/g, " ").trim();
833
- if (safe.length <= MAX_RECAP_SNIPPET_LENGTH) return safe;
834
- return `${safe.slice(0, MAX_RECAP_SNIPPET_LENGTH - 3).trimEnd()}...`;
835
- }
836
- function isRecord2(value) {
837
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
838
- }
839
- function parseTopLevelJson(output) {
840
- const text = output.trim();
841
- if (!text) return null;
842
- const tryParse = (candidate) => {
843
- try {
844
- const parsed = JSON.parse(candidate);
845
- return isRecord2(parsed) ? parsed : null;
846
- } catch {
847
- return null;
848
- }
849
- };
850
- const direct = tryParse(text);
851
- if (direct) return direct;
852
- const findJsonEnd = (start) => {
853
- const open = text[start];
854
- if (open !== "{" && open !== "[") return -1;
855
- const stack = [open];
856
- let inString = false;
857
- let escaped = false;
858
- for (let i = start + 1; i < text.length; i += 1) {
859
- const ch = text[i];
860
- if (inString) {
861
- if (escaped) {
862
- escaped = false;
863
- continue;
864
- }
865
- if (ch === "\\") {
866
- escaped = true;
867
- continue;
868
- }
869
- if (ch === '"') {
870
- inString = false;
871
- }
872
- continue;
873
- }
874
- if (ch === '"') {
875
- inString = true;
876
- continue;
877
- }
878
- if (ch === "{" || ch === "[") {
879
- stack.push(ch);
880
- continue;
881
- }
882
- if (ch === "}" || ch === "]") {
883
- const expected = ch === "}" ? "{" : "[";
884
- const top = stack[stack.length - 1];
885
- if (top !== expected) return -1;
886
- stack.pop();
887
- if (stack.length === 0) {
888
- return i;
889
- }
890
- }
891
- }
892
- return -1;
893
- };
894
- for (let start = 0; start < text.length; start += 1) {
895
- const ch = text[start];
896
- if (ch !== "{" && ch !== "[") continue;
897
- const end = findJsonEnd(start);
898
- if (end < 0) continue;
899
- const parsed = tryParse(text.slice(start, end + 1));
900
- if (parsed) return parsed;
901
- }
902
- return null;
903
- }
904
- function resolveEntryArray(parsed, keys) {
905
- for (const key of keys) {
906
- const value = parsed[key];
907
- if (!Array.isArray(value)) continue;
908
- return value.filter((item) => isRecord2(item));
909
- }
910
- return [];
911
- }
912
- function parseContextJson(output, maxResults) {
913
- const parsed = parseTopLevelJson(output);
914
- if (!parsed) {
915
- return [];
916
- }
917
- const rows = resolveEntryArray(parsed, ["context", "results", "entries", "memories"]);
918
- return rows.slice(0, maxResults).map((entry) => {
919
- const nestedDocument = isRecord2(entry.document) ? entry.document : null;
920
- const title = sanitizeForDisplay(
921
- entry.title ?? nestedDocument?.title ?? nestedDocument?.id ?? entry.path ?? "Untitled"
922
- );
923
- const resolvedPath = sanitizeForDisplay(
924
- entry.path ?? entry.relPath ?? nestedDocument?.path ?? ""
925
- );
926
- const resolvedAge = sanitizeForDisplay(entry.age ?? entry.modified ?? "unknown age");
927
- const snippetSource = String(
928
- entry.snippet ?? entry.text ?? entry.content ?? nestedDocument?.snippet ?? nestedDocument?.content ?? ""
929
- );
930
- return {
931
- title,
932
- path: resolvedPath,
933
- age: resolvedAge,
934
- snippet: truncateSnippet(snippetSource),
935
- score: Number.isFinite(Number(entry.score)) ? Number(entry.score) : 0
936
- };
937
- }).filter((entry) => entry.snippet.length > 0);
938
- }
939
- function parseSessionRecapJson(output, maxResults) {
940
- const parsed = parseTopLevelJson(output);
941
- if (!parsed) {
942
- return [];
943
- }
944
- const rows = resolveEntryArray(parsed, ["messages", "turns", "recap"]);
945
- return rows.map((entry) => {
946
- const role = typeof entry.role === "string" ? entry.role.toLowerCase() : "";
947
- const normalizedRole = role === "user" || role === "human" ? "User" : role === "assistant" || role === "ai" ? "Assistant" : "";
948
- if (!normalizedRole) return null;
949
- const text = truncateRecapSnippet(
950
- typeof entry.text === "string" ? entry.text : typeof entry.content === "string" ? entry.content : ""
951
- );
952
- if (!text) return null;
953
- return {
954
- role: normalizedRole,
955
- text
956
- };
957
- }).filter((entry) => Boolean(entry)).slice(-maxResults);
958
- }
959
837
  function formatSessionContextInjection(recapEntries, memoryEntries) {
960
838
  const lines = [
961
839
  "[ClawVault] Session context restored:",
@@ -983,82 +861,6 @@ function formatSessionContextInjection(recapEntries, memoryEntries) {
983
861
  function resolveVaultPathForAgent(pluginConfig, options = {}) {
984
862
  return findVaultPath(pluginConfig, options);
985
863
  }
986
- function runClawvault(args, pluginConfig, options = {}) {
987
- if (!isOptInEnabled(pluginConfig, "allowClawvaultExec")) {
988
- return {
989
- success: false,
990
- skipped: true,
991
- output: "ClawVault CLI execution is disabled. Set allowClawvaultExec=true to enable.",
992
- code: 0
993
- };
994
- }
995
- const timeoutMs = Number.isFinite(options.timeoutMs) ? Math.max(1e3, Number(options.timeoutMs)) : 15e3;
996
- const executablePath = resolveExecutablePath(CLAWVAULT_EXECUTABLE, {
997
- explicitPath: getConfiguredExecutablePath(pluginConfig)
998
- });
999
- if (!executablePath) {
1000
- return {
1001
- success: false,
1002
- output: "Unable to resolve clawvault executable path.",
1003
- code: 1
1004
- };
1005
- }
1006
- const expectedSha256 = getConfiguredExecutableSha256(pluginConfig);
1007
- const integrityResult = verifyExecutableIntegrity(executablePath, expectedSha256);
1008
- if (!integrityResult.ok) {
1009
- return {
1010
- success: false,
1011
- output: `Executable integrity verification failed for ${executablePath}.`,
1012
- code: 1
1013
- };
1014
- }
1015
- let sanitizedArgs;
1016
- try {
1017
- sanitizedArgs = sanitizeExecArgs(args);
1018
- } catch (error) {
1019
- return {
1020
- success: false,
1021
- output: error instanceof Error ? error.message : "Invalid command arguments",
1022
- code: 1
1023
- };
1024
- }
1025
- try {
1026
- const output = execFileSync(executablePath, sanitizedArgs, {
1027
- encoding: "utf-8",
1028
- timeout: timeoutMs,
1029
- stdio: ["pipe", "pipe", "pipe"],
1030
- shell: false
1031
- });
1032
- return {
1033
- success: true,
1034
- output: output.trim(),
1035
- code: 0
1036
- };
1037
- } catch (error) {
1038
- const details = error;
1039
- return {
1040
- success: false,
1041
- output: details.stderr?.toString() || details.message || "unknown error",
1042
- code: details.status || 1
1043
- };
1044
- }
1045
- }
1046
- function parseRecoveryOutput(output) {
1047
- if (!output || typeof output !== "string") {
1048
- return { hadDeath: false, workingOn: null };
1049
- }
1050
- const hadDeath = output.includes("Context death detected") || output.includes("died") || output.includes("\u26A0\uFE0F");
1051
- if (!hadDeath) {
1052
- return { hadDeath: false, workingOn: null };
1053
- }
1054
- const workingOnLine = output.split("\n").find((line) => line.toLowerCase().includes("working on"));
1055
- if (!workingOnLine) {
1056
- return { hadDeath: true, workingOn: null };
1057
- }
1058
- const parts = workingOnLine.split(":");
1059
- const workingOn = parts.length > 1 ? sanitizeForDisplay(parts.slice(1).join(":").trim()) : null;
1060
- return { hadDeath: true, workingOn: workingOn || null };
1061
- }
1062
864
  function getObserveCursorPath(vaultPath) {
1063
865
  return path3.join(vaultPath, ".clawvault", OBSERVE_CURSOR_FILE);
1064
866
  }
@@ -1141,12 +943,40 @@ function shouldObserveActiveSessions(vaultPath, agentId, pluginConfig) {
1141
943
  return false;
1142
944
  }
1143
945
  function runObserverCron(vaultPath, agentId, pluginConfig, options = {}) {
946
+ if (!isOptInEnabled(pluginConfig, "allowClawvaultExec")) {
947
+ return false;
948
+ }
949
+ const executablePath = resolveExecutablePath(CLAWVAULT_EXECUTABLE, {
950
+ explicitPath: getConfiguredExecutablePath(pluginConfig)
951
+ });
952
+ if (!executablePath) {
953
+ return false;
954
+ }
955
+ const expectedSha256 = getConfiguredExecutableSha256(pluginConfig);
956
+ const integrityResult = verifyExecutableIntegrity(executablePath, expectedSha256);
957
+ if (!integrityResult.ok) {
958
+ return false;
959
+ }
1144
960
  const args = ["observe", "--cron", "--agent", agentId, "-v", vaultPath];
1145
961
  if (Number.isFinite(options.minNewBytes) && Number(options.minNewBytes) > 0) {
1146
962
  args.push("--min-new", String(Math.floor(Number(options.minNewBytes))));
1147
963
  }
1148
- const result = runClawvault(args, pluginConfig, { timeoutMs: 12e4 });
1149
- return !result.skipped && result.success;
964
+ let sanitizedArgs;
965
+ try {
966
+ sanitizedArgs = sanitizeExecArgs(args);
967
+ } catch {
968
+ return false;
969
+ }
970
+ try {
971
+ const child = spawn(executablePath, sanitizedArgs, {
972
+ stdio: "ignore",
973
+ shell: false
974
+ });
975
+ child.unref();
976
+ return true;
977
+ } catch {
978
+ return false;
979
+ }
1150
980
  }
1151
981
  function resolveSessionKey(input) {
1152
982
  return sanitizeSessionKey(input);
@@ -1222,8 +1052,8 @@ function toSafeFilePath(vaultPath, relPath) {
1222
1052
  if (!mapped || mapped.includes("..")) {
1223
1053
  throw new Error("Invalid memory path");
1224
1054
  }
1225
- if (!mapped.toLowerCase().endsWith(".md")) {
1226
- throw new Error("memory_get only allows Markdown note paths inside the vault");
1055
+ if (mapped !== "MEMORY.md" && !mapped.startsWith("memory/")) {
1056
+ throw new Error("memory_get only allows MEMORY.md or memory/* paths");
1227
1057
  }
1228
1058
  const absolute = path4.resolve(vaultPath, mapped);
1229
1059
  const vaultRootWithSep = vaultPath.endsWith(path4.sep) ? vaultPath : `${vaultPath}${path4.sep}`;
@@ -1350,17 +1180,8 @@ function buildToolSchema(properties, required = []) {
1350
1180
  additionalProperties: false
1351
1181
  };
1352
1182
  }
1353
- function resolveToolInput(toolCallIdOrInput, maybeInput) {
1354
- if (maybeInput && typeof maybeInput === "object" && !Array.isArray(maybeInput)) {
1355
- return maybeInput;
1356
- }
1357
- if (toolCallIdOrInput && typeof toolCallIdOrInput === "object" && !Array.isArray(toolCallIdOrInput)) {
1358
- return toolCallIdOrInput;
1359
- }
1360
- return {};
1361
- }
1362
1183
  function createMemorySearchToolFactory(memoryManager) {
1363
- return (_toolContext) => {
1184
+ return () => {
1364
1185
  const inputSchema = buildToolSchema({
1365
1186
  query: {
1366
1187
  type: "string",
@@ -1383,8 +1204,7 @@ function createMemorySearchToolFactory(memoryManager) {
1383
1204
  description: "Optional OpenClaw session key for scoped recall."
1384
1205
  }
1385
1206
  }, ["query"]);
1386
- const execute = async (toolCallIdOrInput, maybeInput) => {
1387
- const input = resolveToolInput(toolCallIdOrInput, maybeInput);
1207
+ const execute = async (input) => {
1388
1208
  const query = typeof input.query === "string" ? input.query : "";
1389
1209
  if (!query.trim()) {
1390
1210
  return { query, count: 0, results: [] };
@@ -1401,7 +1221,6 @@ function createMemorySearchToolFactory(memoryManager) {
1401
1221
  };
1402
1222
  };
1403
1223
  return {
1404
- label: "Memory Search",
1405
1224
  name: "memory_search",
1406
1225
  description: "Search ClawVault memory for relevant snippets before answering.",
1407
1226
  inputSchema,
@@ -1414,15 +1233,11 @@ function createMemorySearchToolFactory(memoryManager) {
1414
1233
  };
1415
1234
  }
1416
1235
  function createMemoryGetToolFactory(memoryManager) {
1417
- return (_toolContext) => {
1236
+ return () => {
1418
1237
  const inputSchema = buildToolSchema({
1419
- path: {
1420
- type: "string",
1421
- description: "Relative path from memory_search result (for OpenClaw compatibility)."
1422
- },
1423
1238
  relPath: {
1424
1239
  type: "string",
1425
- description: "Alias of path (e.g. memory/2026-01-01.md)."
1240
+ description: "Relative path from memory_search result (e.g. memory/2026-01-01.md)."
1426
1241
  },
1427
1242
  from: {
1428
1243
  type: "number",
@@ -1435,11 +1250,9 @@ function createMemoryGetToolFactory(memoryManager) {
1435
1250
  maximum: 400,
1436
1251
  description: "Optional number of lines to read."
1437
1252
  }
1438
- });
1439
- inputSchema.anyOf = [{ required: ["path"] }, { required: ["relPath"] }];
1440
- const execute = async (toolCallIdOrInput, maybeInput) => {
1441
- const input = resolveToolInput(toolCallIdOrInput, maybeInput);
1442
- const relPath = typeof input.path === "string" ? input.path : typeof input.relPath === "string" ? input.relPath : "";
1253
+ }, ["relPath"]);
1254
+ const execute = async (input) => {
1255
+ const relPath = typeof input.relPath === "string" ? input.relPath : "";
1443
1256
  if (!relPath.trim()) {
1444
1257
  return { path: relPath, text: "" };
1445
1258
  }
@@ -1450,7 +1263,6 @@ function createMemoryGetToolFactory(memoryManager) {
1450
1263
  });
1451
1264
  };
1452
1265
  return {
1453
- label: "Memory Get",
1454
1266
  name: "memory_get",
1455
1267
  description: "Read a specific memory file or line range from ClawVault.",
1456
1268
  inputSchema,
@@ -1575,20 +1387,82 @@ function rewriteQuestionWithMemoryEvidence(originalContent, memoryHits) {
1575
1387
  }
1576
1388
 
1577
1389
  // src/plugin/vault-context-injector.ts
1390
+ import * as path5 from "path";
1578
1391
  var DEFAULT_MAX_CONTEXT_RESULTS = 4;
1579
1392
  var DEFAULT_MAX_RECAP_RESULTS = 6;
1393
+ var DEFAULT_MIN_SCORE2 = 0.2;
1394
+ var MAX_CONTEXT_SNIPPET_LENGTH = 220;
1395
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
1396
+ function clamp2(value, min, max) {
1397
+ return Math.max(min, Math.min(max, value));
1398
+ }
1399
+ function truncateContextSnippet(snippet) {
1400
+ const normalized = sanitizeForDisplay(snippet).replace(/\s+/g, " ").trim();
1401
+ if (normalized.length <= MAX_CONTEXT_SNIPPET_LENGTH) {
1402
+ return normalized;
1403
+ }
1404
+ return `${normalized.slice(0, MAX_CONTEXT_SNIPPET_LENGTH - 3).trimEnd()}...`;
1405
+ }
1406
+ function toRelativeVaultPath(vaultPath, absolutePath) {
1407
+ const rel = path5.relative(vaultPath, absolutePath).replace(/\\/g, "/");
1408
+ return rel.startsWith(".") ? path5.basename(absolutePath) : rel;
1409
+ }
1410
+ function formatAgeLabel(modifiedAt) {
1411
+ const modified = modifiedAt.getTime();
1412
+ if (!Number.isFinite(modified)) {
1413
+ return "unknown age";
1414
+ }
1415
+ const elapsedMs = Date.now() - modified;
1416
+ if (elapsedMs < ONE_DAY_MS) {
1417
+ return "today";
1418
+ }
1419
+ const days = Math.max(1, Math.floor(elapsedMs / ONE_DAY_MS));
1420
+ if (days < 7) {
1421
+ return `${days}d ago`;
1422
+ }
1423
+ const weeks = Math.floor(days / 7);
1424
+ if (weeks < 5) {
1425
+ return `${weeks}w ago`;
1426
+ }
1427
+ const months = Math.floor(days / 30);
1428
+ if (months < 12) {
1429
+ return `${months}mo ago`;
1430
+ }
1431
+ const years = Math.floor(days / 365);
1432
+ return `${years}y ago`;
1433
+ }
1434
+ function mapSearchResultToContextEntry(vaultPath, result) {
1435
+ const snippet = truncateContextSnippet(result.snippet);
1436
+ if (!snippet) {
1437
+ return null;
1438
+ }
1439
+ return {
1440
+ title: sanitizeForDisplay(result.document.title || "Untitled"),
1441
+ path: sanitizeForDisplay(toRelativeVaultPath(vaultPath, result.document.path)),
1442
+ age: formatAgeLabel(result.document.modified),
1443
+ snippet,
1444
+ score: Number.isFinite(result.score) ? result.score : 0
1445
+ };
1446
+ }
1580
1447
  async function fetchSessionRecapEntries(options) {
1581
1448
  const sessionKey = resolveSessionKey(options.sessionKey);
1582
1449
  if (!sessionKey) return [];
1583
- const recapArgs = ["session-recap", sessionKey, "--format", "json"];
1584
- if (options.agentId) {
1585
- recapArgs.push("--agent", options.agentId);
1586
- }
1587
- const recapResult = runClawvault(recapArgs, options.pluginConfig, { timeoutMs: 2e4 });
1588
- if (!recapResult.success) {
1450
+ try {
1451
+ const recap = await buildSessionRecap(sessionKey, {
1452
+ agentId: options.agentId,
1453
+ limit: DEFAULT_MAX_RECAP_RESULTS
1454
+ });
1455
+ return recap.messages.slice(-DEFAULT_MAX_RECAP_RESULTS).map((entry) => {
1456
+ const text = sanitizeForDisplay(entry.text);
1457
+ if (!text) return null;
1458
+ return {
1459
+ role: entry.role === "user" ? "User" : "Assistant",
1460
+ text
1461
+ };
1462
+ }).filter((entry) => Boolean(entry));
1463
+ } catch {
1589
1464
  return [];
1590
1465
  }
1591
- return parseSessionRecapJson(recapResult.output, DEFAULT_MAX_RECAP_RESULTS);
1592
1466
  }
1593
1467
  async function fetchMemoryContextEntries(options) {
1594
1468
  const prompt = sanitizePromptForContext(options.prompt);
@@ -1602,44 +1476,20 @@ async function fetchMemoryContextEntries(options) {
1602
1476
  if (!vaultPath) {
1603
1477
  return { entries: [], vaultPath: null };
1604
1478
  }
1605
- const maxResults = Number.isFinite(options.maxResults) ? Math.max(1, Math.min(20, Number(options.maxResults))) : DEFAULT_MAX_CONTEXT_RESULTS;
1606
- const profile = options.contextProfile ?? options.pluginConfig.contextProfile ?? "auto";
1607
- const contextArgs = [
1608
- "context",
1609
- prompt,
1610
- "--format",
1611
- "json",
1612
- "--profile",
1613
- profile,
1614
- "--limit",
1615
- String(maxResults),
1616
- "-v",
1617
- vaultPath
1618
- ];
1619
- const contextResult = runClawvault(contextArgs, options.pluginConfig, { timeoutMs: 25e3 });
1620
- if (contextResult.success) {
1621
- return {
1622
- entries: parseContextJson(contextResult.output, maxResults),
1623
- vaultPath
1624
- };
1625
- }
1626
- const fallbackSearchArgs = [
1627
- "search",
1628
- prompt,
1629
- "--json",
1630
- "-n",
1631
- String(maxResults),
1632
- "-v",
1633
- vaultPath
1634
- ];
1635
- const fallbackSearchResult = runClawvault(fallbackSearchArgs, options.pluginConfig, { timeoutMs: 25e3 });
1636
- if (!fallbackSearchResult.success) {
1479
+ const maxResults = Number.isFinite(options.maxResults) ? clamp2(Math.floor(Number(options.maxResults)), 1, 20) : DEFAULT_MAX_CONTEXT_RESULTS;
1480
+ try {
1481
+ const vault = new ClawVault(vaultPath);
1482
+ await vault.load();
1483
+ const matches = await vault.find(prompt, {
1484
+ limit: maxResults,
1485
+ minScore: DEFAULT_MIN_SCORE2,
1486
+ temporalBoost: true
1487
+ });
1488
+ const entries = matches.map((match) => mapSearchResultToContextEntry(vaultPath, match)).filter((entry) => Boolean(entry));
1489
+ return { entries, vaultPath };
1490
+ } catch {
1637
1491
  return { entries: [], vaultPath };
1638
1492
  }
1639
- return {
1640
- entries: parseContextJson(fallbackSearchResult.output, maxResults),
1641
- vaultPath
1642
- };
1643
1493
  }
1644
1494
  async function buildVaultContextInjection(options) {
1645
1495
  const [recapEntries, memoryResult] = await Promise.all([
@@ -1761,13 +1611,13 @@ function createMessageSendingHandler(dependencies) {
1761
1611
 
1762
1612
  // src/plugin/fact-extractor.ts
1763
1613
  import * as fs5 from "fs";
1764
- import * as path5 from "path";
1614
+ import * as path6 from "path";
1765
1615
  import { createHash as createHash2 } from "crypto";
1766
1616
  var FACTS_FILE = "facts.jsonl";
1767
1617
  var ENTITY_GRAPH_FILE = "entity-graph.json";
1768
1618
  var MAX_TEXT_LENGTH = 6e3;
1769
1619
  function ensureClawVaultDir(vaultPath) {
1770
- const dir = path5.join(vaultPath, ".clawvault");
1620
+ const dir = path6.join(vaultPath, ".clawvault");
1771
1621
  if (!fs5.existsSync(dir)) {
1772
1622
  fs5.mkdirSync(dir, { recursive: true });
1773
1623
  }
@@ -1887,7 +1737,7 @@ function buildEntityGraph(facts) {
1887
1737
  };
1888
1738
  }
1889
1739
  function ensureFactsLogFile(vaultPath) {
1890
- const filePath = path5.join(ensureClawVaultDir(vaultPath), FACTS_FILE);
1740
+ const filePath = path6.join(ensureClawVaultDir(vaultPath), FACTS_FILE);
1891
1741
  if (!fs5.existsSync(filePath)) {
1892
1742
  fs5.writeFileSync(filePath, "", "utf-8");
1893
1743
  }
@@ -1900,7 +1750,7 @@ function persistFactsAndGraph(vaultPath, extractedFacts) {
1900
1750
  store.save();
1901
1751
  const allFacts = store.getAllFacts();
1902
1752
  const graph = buildEntityGraph(allFacts);
1903
- const graphPath = path5.join(ensureClawVaultDir(vaultPath), ENTITY_GRAPH_FILE);
1753
+ const graphPath = path6.join(ensureClawVaultDir(vaultPath), ENTITY_GRAPH_FILE);
1904
1754
  fs5.writeFileSync(graphPath, `${JSON.stringify(graph, null, 2)}
1905
1755
  `, "utf-8");
1906
1756
  return {
@@ -1957,13 +1807,13 @@ async function runWeeklyReflectionIfNeeded(deps, agentId, workspaceDir) {
1957
1807
  if (!vaultPath) {
1958
1808
  return;
1959
1809
  }
1960
- const result = runClawvault(["reflect", "-v", vaultPath], deps.pluginConfig, {
1961
- timeoutMs: 12e4
1962
- });
1963
- if (result.success) {
1810
+ try {
1811
+ const result = await runReflection({ vaultPath });
1812
+ if (result.writtenWeeks > 0) {
1813
+ deps.logger?.info("[clawvault] Weekly reflection complete");
1814
+ }
1964
1815
  deps.runtimeState.markWeeklyReflectionRun(weekKey);
1965
- deps.logger?.info("[clawvault] Weekly reflection complete");
1966
- } else if (!result.skipped) {
1816
+ } catch {
1967
1817
  deps.logger?.warn("[clawvault] Weekly reflection failed");
1968
1818
  }
1969
1819
  }
@@ -1977,19 +1827,16 @@ async function handleGatewayStart(event, ctx, deps) {
1977
1827
  deps.logger?.warn("[clawvault] No vault found, skipping startup recovery");
1978
1828
  return;
1979
1829
  }
1980
- const result = runClawvault(["recover", "--clear", "-v", vaultPath], deps.pluginConfig, {
1981
- timeoutMs: 2e4
1982
- });
1983
- if (result.skipped) {
1984
- return;
1985
- }
1986
- if (!result.success) {
1830
+ let recoveryInfo;
1831
+ try {
1832
+ recoveryInfo = await recover(vaultPath, { clearFlag: true });
1833
+ } catch {
1987
1834
  deps.logger?.warn("[clawvault] Startup recovery command failed");
1988
1835
  return;
1989
1836
  }
1990
- const parsed = parseRecoveryOutput(result.output);
1991
- if (parsed.hadDeath) {
1992
- const message = parsed.workingOn ? `[ClawVault] Context death detected. Last working on: ${parsed.workingOn}. Run \`clawvault wake\` for full recovery context.` : "[ClawVault] Context death detected. Run `clawvault wake` for full recovery context.";
1837
+ if (recoveryInfo.died) {
1838
+ const workingOn = recoveryInfo.checkpoint?.workingOn?.trim();
1839
+ const message = workingOn ? `[ClawVault] Context death detected. Last working on: ${workingOn}. Run \`clawvault wake\` for full recovery context.` : "[ClawVault] Context death detected. Run `clawvault wake` for full recovery context.";
1993
1840
  deps.runtimeState.setStartupRecoveryNotice(message);
1994
1841
  deps.logger?.warn("[clawvault] Context death detected at startup");
1995
1842
  }
@@ -2036,16 +1883,14 @@ async function handleBeforeReset(event, ctx, deps) {
2036
1883
  if (autoCheckpointEnabled) {
2037
1884
  const safeSessionKey = sanitizeForCheckpoint(sessionKey, 120);
2038
1885
  const safeReason = sanitizeForCheckpoint(event.reason ?? "before_reset", 80);
2039
- const checkpointResult = runClawvault([
2040
- "checkpoint",
2041
- "--working-on",
2042
- `Session reset via ${safeReason}`,
2043
- "--focus",
2044
- `Pre-reset checkpoint, session: ${safeSessionKey}`,
2045
- "-v",
2046
- vaultPath
2047
- ], deps.pluginConfig, { timeoutMs: 3e4 });
2048
- if (!checkpointResult.success && !checkpointResult.skipped) {
1886
+ try {
1887
+ await checkpoint({
1888
+ workingOn: `Session reset via ${safeReason}`,
1889
+ focus: `Pre-reset checkpoint, session: ${safeSessionKey}`,
1890
+ vaultPath
1891
+ });
1892
+ await flush();
1893
+ } catch {
2049
1894
  deps.logger?.warn("[clawvault] Auto-checkpoint before reset failed");
2050
1895
  }
2051
1896
  }
@@ -2120,7 +1965,7 @@ function isOpenClawPluginApi(value) {
2120
1965
  const record = value;
2121
1966
  return typeof record.on === "function" && typeof record.registerTool === "function" && typeof record.logger === "object";
2122
1967
  }
2123
- async function registerOpenClawPlugin(api) {
1968
+ function registerOpenClawPlugin(api) {
2124
1969
  const pluginConfig = readPluginConfig(api);
2125
1970
  const runtimeState = new ClawVaultPluginRuntimeState();
2126
1971
  const memoryManager = new ClawVaultMemoryManager({
@@ -2131,10 +1976,8 @@ async function registerOpenClawPlugin(api) {
2131
1976
  warn: api.logger.warn
2132
1977
  }
2133
1978
  });
2134
- const memorySearchTool = createMemorySearchToolFactory(memoryManager)();
2135
- const memoryGetTool = createMemoryGetToolFactory(memoryManager)();
2136
- api.registerTool(memorySearchTool, { name: "memory_search" });
2137
- api.registerTool(memoryGetTool, { name: "memory_get" });
1979
+ api.registerTool(createMemorySearchToolFactory(memoryManager), { name: "memory_search" });
1980
+ api.registerTool(createMemoryGetToolFactory(memoryManager), { name: "memory_get" });
2138
1981
  api.on("before_prompt_build", createBeforePromptBuildHandler({
2139
1982
  pluginConfig,
2140
1983
  runtimeState
@@ -2196,7 +2039,7 @@ var clawvaultPlugin = {
2196
2039
  name: "ClawVault",
2197
2040
  kind: "memory",
2198
2041
  description: "Structured memory system for AI agents with proactive recall and protocol-safe messaging",
2199
- async register(apiOrRuntime) {
2042
+ register(apiOrRuntime) {
2200
2043
  if (isOpenClawPluginApi(apiOrRuntime)) {
2201
2044
  return registerOpenClawPlugin(apiOrRuntime);
2202
2045
  }