@joshuaswarren/openclaw-engram 8.3.64 → 8.3.65

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.
package/dist/index.js CHANGED
@@ -10919,6 +10919,92 @@ async function readAllEdges(memoryDir, config) {
10919
10919
  ]);
10920
10920
  return parts.flat();
10921
10921
  }
10922
+ function isValidGraphEdge(raw, expectedType) {
10923
+ if (!raw || typeof raw !== "object") return false;
10924
+ const edge = raw;
10925
+ return edge.type === expectedType && typeof edge.from === "string" && edge.from.length > 0 && typeof edge.to === "string" && edge.to.length > 0 && typeof edge.weight === "number" && Number.isFinite(edge.weight) && typeof edge.label === "string" && typeof edge.ts === "string";
10926
+ }
10927
+ async function analyzeGraphHealth(memoryDir, options) {
10928
+ const enabledTypes = [];
10929
+ if (options?.entityGraphEnabled !== false) enabledTypes.push("entity");
10930
+ if (options?.timeGraphEnabled !== false) enabledTypes.push("time");
10931
+ if (options?.causalGraphEnabled !== false) enabledTypes.push("causal");
10932
+ const files = [];
10933
+ const globalNodes = /* @__PURE__ */ new Set();
10934
+ for (const type of enabledTypes) {
10935
+ const filePath = graphFilePath(memoryDir, type);
10936
+ let exists3 = true;
10937
+ let totalLines = 0;
10938
+ let validEdges = 0;
10939
+ let corruptLines = 0;
10940
+ const nodes = /* @__PURE__ */ new Set();
10941
+ try {
10942
+ const raw = await readFile14(filePath, "utf8");
10943
+ for (const line of raw.split("\n")) {
10944
+ const trimmed = line.trim();
10945
+ if (!trimmed) continue;
10946
+ totalLines += 1;
10947
+ try {
10948
+ const parsed = JSON.parse(trimmed);
10949
+ if (!isValidGraphEdge(parsed, type)) {
10950
+ corruptLines += 1;
10951
+ continue;
10952
+ }
10953
+ validEdges += 1;
10954
+ nodes.add(parsed.from);
10955
+ nodes.add(parsed.to);
10956
+ globalNodes.add(parsed.from);
10957
+ globalNodes.add(parsed.to);
10958
+ } catch {
10959
+ corruptLines += 1;
10960
+ }
10961
+ }
10962
+ } catch {
10963
+ exists3 = false;
10964
+ }
10965
+ files.push({
10966
+ type,
10967
+ filePath,
10968
+ exists: exists3,
10969
+ totalLines,
10970
+ validEdges,
10971
+ corruptLines,
10972
+ uniqueNodes: nodes.size
10973
+ });
10974
+ }
10975
+ const totals = files.reduce(
10976
+ (acc, item) => {
10977
+ acc.totalLines += item.totalLines;
10978
+ acc.validEdges += item.validEdges;
10979
+ acc.corruptLines += item.corruptLines;
10980
+ return acc;
10981
+ },
10982
+ {
10983
+ totalLines: 0,
10984
+ validEdges: 0,
10985
+ corruptLines: 0,
10986
+ uniqueNodes: globalNodes.size
10987
+ }
10988
+ );
10989
+ totals.uniqueNodes = globalNodes.size;
10990
+ const report = {
10991
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10992
+ enabledTypes,
10993
+ totals,
10994
+ files
10995
+ };
10996
+ if (options?.includeRepairGuidance === true) {
10997
+ const guidance = [];
10998
+ if (totals.corruptLines > 0) {
10999
+ guidance.push("Corrupt graph lines detected: back up memory/state/graphs, then rebuild graphs from clean memory replay/extraction runs.");
11000
+ }
11001
+ if (totals.validEdges === 0) {
11002
+ guidance.push("No valid edges detected yet: run normal extraction traffic (or replay ingestion) to seed graph files.");
11003
+ }
11004
+ if (guidance.length > 0) report.repairGuidance = guidance;
11005
+ }
11006
+ return report;
11007
+ }
10922
11008
  function detectCausalPhrase(text) {
10923
11009
  const lower = text.toLowerCase();
10924
11010
  for (const phrase of CAUSAL_PHRASES) {
@@ -20823,6 +20909,14 @@ async function runMigrateObservationsCliCommand(options) {
20823
20909
  async function runConversationIndexHealthCliCommand(orchestrator) {
20824
20910
  return orchestrator.getConversationIndexHealth();
20825
20911
  }
20912
+ async function runGraphHealthCliCommand(options) {
20913
+ return analyzeGraphHealth(options.memoryDir, {
20914
+ entityGraphEnabled: options.entityGraphEnabled,
20915
+ timeGraphEnabled: options.timeGraphEnabled,
20916
+ causalGraphEnabled: options.causalGraphEnabled,
20917
+ includeRepairGuidance: options.includeRepairGuidance
20918
+ });
20919
+ }
20826
20920
  async function runTailscaleStatusCliCommand(options = {}) {
20827
20921
  const helper = options.helper ?? new TailscaleHelper({ timeoutMs: options.timeoutMs });
20828
20922
  return helper.status();
@@ -21454,6 +21548,18 @@ function registerCli(api, orchestrator) {
21454
21548
  console.log(JSON.stringify(health, null, 2));
21455
21549
  console.log("OK");
21456
21550
  });
21551
+ cmd.command("graph-health").description("Show graph edge-file integrity, node coverage, and corruption counts").option("--repair-guidance", "Include non-destructive repair guidance").action(async (...args) => {
21552
+ const options = args[0] ?? {};
21553
+ const report = await runGraphHealthCliCommand({
21554
+ memoryDir: orchestrator.config.memoryDir,
21555
+ entityGraphEnabled: orchestrator.config.entityGraphEnabled,
21556
+ timeGraphEnabled: orchestrator.config.timeGraphEnabled,
21557
+ causalGraphEnabled: orchestrator.config.causalGraphEnabled,
21558
+ includeRepairGuidance: options.repairGuidance === true
21559
+ });
21560
+ console.log(JSON.stringify(report, null, 2));
21561
+ console.log("OK");
21562
+ });
21457
21563
  cmd.command("tailscale-status").description("Show Tailscale availability and daemon status").option("--timeout-ms <n>", "Command timeout in milliseconds", "10000").action(async (...args) => {
21458
21564
  const options = args[0] ?? {};
21459
21565
  const timeoutMsRaw = parseInt(String(options.timeoutMs ?? "10000"), 10);