@joshuaswarren/openclaw-engram 9.0.37 → 9.0.39

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
@@ -304,6 +304,8 @@ function parseConfig(raw) {
304
304
  memoryRedTeamBenchEnabled: cfg.memoryRedTeamBenchEnabled === true,
305
305
  harmonicRetrievalEnabled: cfg.harmonicRetrievalEnabled === true,
306
306
  abstractionAnchorsEnabled: cfg.abstractionAnchorsEnabled === true,
307
+ verifiedRecallEnabled: cfg.verifiedRecallEnabled === true,
308
+ semanticRulePromotionEnabled: cfg.semanticRulePromotionEnabled === true,
307
309
  abstractionNodeStoreDir: typeof cfg.abstractionNodeStoreDir === "string" && cfg.abstractionNodeStoreDir.trim().length > 0 ? cfg.abstractionNodeStoreDir.trim() : path.join(memoryDir, "state", "abstraction-nodes"),
308
310
  // Local LLM Provider (v2.1)
309
311
  localLlmEnabled: cfg.localLlmEnabled === true || cfg.localLlmEnabled === "true",
@@ -581,6 +583,18 @@ function buildDefaultRecallPipeline(cfg) {
581
583
  maxResults: 3,
582
584
  maxChars: 1800
583
585
  },
586
+ {
587
+ id: "harmonic-retrieval",
588
+ enabled: cfg.harmonicRetrievalEnabled === true,
589
+ maxResults: 3,
590
+ maxChars: 2200
591
+ },
592
+ {
593
+ id: "verified-episodes",
594
+ enabled: cfg.verifiedRecallEnabled === true,
595
+ maxResults: 3,
596
+ maxChars: 1800
597
+ },
584
598
  {
585
599
  id: "memories",
586
600
  enabled: true,
@@ -628,10 +642,10 @@ function buildRecallPipelineConfig(cfg) {
628
642
  }
629
643
 
630
644
  // src/orchestrator.ts
631
- import path34 from "path";
645
+ import path37 from "path";
632
646
  import os5 from "os";
633
647
  import { createHash as createHash6 } from "crypto";
634
- import { mkdir as mkdir24, readdir as readdir16, readFile as readFile23, stat as stat7, unlink as unlink5, writeFile as writeFile24 } from "fs/promises";
648
+ import { mkdir as mkdir26, readdir as readdir16, readFile as readFile23, stat as stat7, unlink as unlink5, writeFile as writeFile26 } from "fs/promises";
635
649
 
636
650
  // src/signal.ts
637
651
  var BUILTIN_HIGH_PATTERNS = [
@@ -15021,6 +15035,401 @@ async function getTrustZoneStoreStatus(options) {
15021
15035
  };
15022
15036
  }
15023
15037
 
15038
+ // src/harmonic-retrieval.ts
15039
+ import path27 from "path";
15040
+
15041
+ // src/abstraction-nodes.ts
15042
+ import path25 from "path";
15043
+ import { mkdir as mkdir18, writeFile as writeFile19 } from "fs/promises";
15044
+ function validateKind2(raw) {
15045
+ const value = assertString2(raw, "kind");
15046
+ if (!["episode", "topic", "project", "workflow", "constraint"].includes(value)) {
15047
+ throw new Error("kind must be one of episode|topic|project|workflow|constraint");
15048
+ }
15049
+ return value;
15050
+ }
15051
+ function validateLevel(raw) {
15052
+ const value = assertString2(raw, "abstractionLevel");
15053
+ if (!["micro", "meso", "macro"].includes(value)) {
15054
+ throw new Error("abstractionLevel must be one of micro|meso|macro");
15055
+ }
15056
+ return value;
15057
+ }
15058
+ function resolveAbstractionNodeStoreDir(memoryDir, overrideDir) {
15059
+ if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
15060
+ return overrideDir.trim();
15061
+ }
15062
+ return path25.join(memoryDir, "state", "abstraction-nodes");
15063
+ }
15064
+ function validateAbstractionNode(raw) {
15065
+ if (!isRecord2(raw)) throw new Error("abstraction node must be an object");
15066
+ if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
15067
+ return {
15068
+ schemaVersion: 1,
15069
+ nodeId: assertSafePathSegment(assertString2(raw.nodeId, "nodeId"), "nodeId"),
15070
+ recordedAt: assertIsoRecordedAt(assertString2(raw.recordedAt, "recordedAt")),
15071
+ sessionKey: assertString2(raw.sessionKey, "sessionKey"),
15072
+ kind: validateKind2(raw.kind),
15073
+ abstractionLevel: validateLevel(raw.abstractionLevel),
15074
+ title: assertString2(raw.title, "title"),
15075
+ summary: assertString2(raw.summary, "summary"),
15076
+ sourceMemoryIds: optionalStringArray2(raw.sourceMemoryIds, "sourceMemoryIds"),
15077
+ entityRefs: optionalStringArray2(raw.entityRefs, "entityRefs"),
15078
+ tags: optionalStringArray2(raw.tags, "tags"),
15079
+ metadata: validateStringRecord(raw.metadata, "metadata")
15080
+ };
15081
+ }
15082
+ async function getAbstractionNodeStoreStatus(options) {
15083
+ const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
15084
+ const nodesDir = path25.join(rootDir, "nodes");
15085
+ const files = await listJsonFiles(nodesDir);
15086
+ const nodes = [];
15087
+ const invalidNodes = [];
15088
+ for (const filePath of files) {
15089
+ try {
15090
+ nodes.push(validateAbstractionNode(await readJsonFile(filePath)));
15091
+ } catch (error) {
15092
+ invalidNodes.push({
15093
+ path: filePath,
15094
+ error: error instanceof Error ? error.message : String(error)
15095
+ });
15096
+ }
15097
+ }
15098
+ nodes.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
15099
+ const byKind = {};
15100
+ const byLevel = {};
15101
+ for (const node of nodes) {
15102
+ byKind[node.kind] = (byKind[node.kind] ?? 0) + 1;
15103
+ byLevel[node.abstractionLevel] = (byLevel[node.abstractionLevel] ?? 0) + 1;
15104
+ }
15105
+ return {
15106
+ enabled: options.enabled,
15107
+ anchorsEnabled: options.anchorsEnabled,
15108
+ rootDir,
15109
+ nodesDir,
15110
+ nodes: {
15111
+ total: files.length,
15112
+ valid: nodes.length,
15113
+ invalid: invalidNodes.length,
15114
+ byKind,
15115
+ byLevel,
15116
+ latestNodeId: nodes[0]?.nodeId,
15117
+ latestRecordedAt: nodes[0]?.recordedAt,
15118
+ latestSessionKey: nodes[0]?.sessionKey
15119
+ },
15120
+ latestNode: nodes[0],
15121
+ invalidNodes
15122
+ };
15123
+ }
15124
+
15125
+ // src/cue-anchors.ts
15126
+ import path26 from "path";
15127
+ import { mkdir as mkdir19, writeFile as writeFile20 } from "fs/promises";
15128
+ function validateAnchorType(raw) {
15129
+ const value = assertString2(raw, "anchorType");
15130
+ if (!["entity", "file", "tool", "outcome", "constraint", "date"].includes(value)) {
15131
+ throw new Error("anchorType must be one of entity|file|tool|outcome|constraint|date");
15132
+ }
15133
+ return value;
15134
+ }
15135
+ function validateNodeRefs(raw) {
15136
+ const nodeRefs = optionalStringArray2(raw, "nodeRefs");
15137
+ if (!nodeRefs || nodeRefs.length === 0) {
15138
+ throw new Error("nodeRefs must contain at least one node reference");
15139
+ }
15140
+ return nodeRefs.map((nodeRef, index) => assertSafePathSegment(nodeRef, `nodeRefs[${index}]`));
15141
+ }
15142
+ function resolveCueAnchorStoreDir(abstractionNodeStoreDir, overrideDir) {
15143
+ if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
15144
+ return overrideDir.trim();
15145
+ }
15146
+ return path26.join(abstractionNodeStoreDir, "anchors");
15147
+ }
15148
+ function validateCueAnchor(raw) {
15149
+ if (!isRecord2(raw)) throw new Error("cue anchor must be an object");
15150
+ if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
15151
+ return {
15152
+ schemaVersion: 1,
15153
+ anchorId: assertSafePathSegment(assertString2(raw.anchorId, "anchorId"), "anchorId"),
15154
+ anchorType: validateAnchorType(raw.anchorType),
15155
+ anchorValue: assertString2(raw.anchorValue, "anchorValue"),
15156
+ normalizedCue: assertString2(raw.normalizedCue, "normalizedCue"),
15157
+ recordedAt: assertIsoRecordedAt(assertString2(raw.recordedAt, "recordedAt")),
15158
+ sessionKey: assertString2(raw.sessionKey, "sessionKey"),
15159
+ nodeRefs: validateNodeRefs(raw.nodeRefs),
15160
+ tags: optionalStringArray2(raw.tags, "tags"),
15161
+ metadata: validateStringRecord(raw.metadata, "metadata")
15162
+ };
15163
+ }
15164
+ async function getCueAnchorStoreStatus(options) {
15165
+ const abstractionNodeStoreDir = options.abstractionNodeStoreDir?.trim().length ? options.abstractionNodeStoreDir.trim() : path26.join(options.memoryDir, "state", "abstraction-nodes");
15166
+ const rootDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
15167
+ const files = await listJsonFiles(rootDir);
15168
+ const anchors = [];
15169
+ const invalidAnchors = [];
15170
+ for (const filePath of files) {
15171
+ try {
15172
+ anchors.push(validateCueAnchor(await readJsonFile(filePath)));
15173
+ } catch (error) {
15174
+ invalidAnchors.push({
15175
+ path: filePath,
15176
+ error: error instanceof Error ? error.message : String(error)
15177
+ });
15178
+ }
15179
+ }
15180
+ anchors.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
15181
+ const byType = {};
15182
+ let totalNodeRefs = 0;
15183
+ for (const anchor of anchors) {
15184
+ byType[anchor.anchorType] = (byType[anchor.anchorType] ?? 0) + 1;
15185
+ totalNodeRefs += anchor.nodeRefs.length;
15186
+ }
15187
+ return {
15188
+ enabled: options.enabled,
15189
+ anchorsEnabled: options.anchorsEnabled,
15190
+ rootDir,
15191
+ anchors: {
15192
+ total: files.length,
15193
+ valid: anchors.length,
15194
+ invalid: invalidAnchors.length,
15195
+ byType,
15196
+ totalNodeRefs,
15197
+ latestAnchorId: anchors[0]?.anchorId,
15198
+ latestRecordedAt: anchors[0]?.recordedAt,
15199
+ latestSessionKey: anchors[0]?.sessionKey
15200
+ },
15201
+ latestAnchor: anchors[0],
15202
+ invalidAnchors
15203
+ };
15204
+ }
15205
+
15206
+ // src/harmonic-retrieval.ts
15207
+ function scoreNode(node, queryTokens) {
15208
+ const matchedFields = [];
15209
+ let score = 0;
15210
+ const titleMatches = countRecallTokenOverlap(queryTokens, node.title);
15211
+ if (titleMatches > 0) {
15212
+ score += titleMatches * 3;
15213
+ matchedFields.push("title");
15214
+ }
15215
+ const summaryMatches = countRecallTokenOverlap(queryTokens, node.summary);
15216
+ if (summaryMatches > 0) {
15217
+ score += summaryMatches * 3;
15218
+ matchedFields.push("summary");
15219
+ }
15220
+ const tagMatches = countRecallTokenOverlap(queryTokens, node.tags?.join(" "));
15221
+ if (tagMatches > 0) {
15222
+ score += tagMatches * 2;
15223
+ matchedFields.push("tags");
15224
+ }
15225
+ const entityMatches = countRecallTokenOverlap(queryTokens, node.entityRefs?.join(" "));
15226
+ if (entityMatches > 0) {
15227
+ score += entityMatches * 2;
15228
+ matchedFields.push("entityRefs");
15229
+ }
15230
+ const kindMatches = countRecallTokenOverlap(queryTokens, `${node.kind} ${node.abstractionLevel}`);
15231
+ if (kindMatches > 0) {
15232
+ score += kindMatches;
15233
+ matchedFields.push("kind");
15234
+ }
15235
+ return { score, matchedFields };
15236
+ }
15237
+ function scoreAnchor(anchor, queryTokens) {
15238
+ const matchedFields = [];
15239
+ let score = 0;
15240
+ const valueMatches = countRecallTokenOverlap(queryTokens, anchor.anchorValue);
15241
+ const normalizedMatches = countRecallTokenOverlap(queryTokens, anchor.normalizedCue);
15242
+ const cueMatches = Math.max(valueMatches, normalizedMatches);
15243
+ if (cueMatches > 0) {
15244
+ score += cueMatches * 4;
15245
+ if (valueMatches > 0) matchedFields.push("anchorValue");
15246
+ if (normalizedMatches > 0) matchedFields.push("anchor");
15247
+ }
15248
+ const typeMatches = countRecallTokenOverlap(queryTokens, anchor.anchorType);
15249
+ if (typeMatches > 0) {
15250
+ score += typeMatches;
15251
+ matchedFields.push("anchorType");
15252
+ }
15253
+ const tagMatches = countRecallTokenOverlap(queryTokens, anchor.tags?.join(" "));
15254
+ if (tagMatches > 0) {
15255
+ score += tagMatches * 2;
15256
+ matchedFields.push("anchorTags");
15257
+ }
15258
+ return { score, matchedFields };
15259
+ }
15260
+ async function readAbstractionNodes(options) {
15261
+ const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
15262
+ const files = await listJsonFiles(path27.join(rootDir, "nodes"));
15263
+ const nodes = [];
15264
+ for (const filePath of files) {
15265
+ try {
15266
+ nodes.push(validateAbstractionNode(await readJsonFile(filePath)));
15267
+ } catch {
15268
+ }
15269
+ }
15270
+ return nodes;
15271
+ }
15272
+ async function readCueAnchors(options) {
15273
+ const abstractionRoot = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
15274
+ const rootDir = resolveCueAnchorStoreDir(abstractionRoot);
15275
+ const files = await listJsonFiles(rootDir);
15276
+ const anchors = [];
15277
+ for (const filePath of files) {
15278
+ try {
15279
+ anchors.push(validateCueAnchor(await readJsonFile(filePath)));
15280
+ } catch {
15281
+ }
15282
+ }
15283
+ return anchors;
15284
+ }
15285
+ async function searchHarmonicRetrieval(options) {
15286
+ const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
15287
+ if (queryTokens.size === 0 || options.maxResults <= 0) return [];
15288
+ const nodes = await readAbstractionNodes(options);
15289
+ const candidates = /* @__PURE__ */ new Map();
15290
+ for (const node of nodes) {
15291
+ const { score, matchedFields } = scoreNode(node, queryTokens);
15292
+ if (score <= 0) continue;
15293
+ candidates.set(node.nodeId, {
15294
+ node,
15295
+ nodeScore: score,
15296
+ anchorScore: 0,
15297
+ matchedFields: new Set(matchedFields),
15298
+ matchedAnchors: /* @__PURE__ */ new Map()
15299
+ });
15300
+ }
15301
+ if (options.anchorsEnabled) {
15302
+ const anchors = await readCueAnchors(options);
15303
+ const nodeIndex = new Map(nodes.map((node) => [node.nodeId, node]));
15304
+ for (const anchor of anchors) {
15305
+ const { score, matchedFields } = scoreAnchor(anchor, queryTokens);
15306
+ if (score <= 0) continue;
15307
+ for (const nodeRef of anchor.nodeRefs) {
15308
+ const node = nodeIndex.get(nodeRef);
15309
+ if (!node) continue;
15310
+ const existing = candidates.get(nodeRef) ?? {
15311
+ node,
15312
+ nodeScore: 0,
15313
+ anchorScore: 0,
15314
+ matchedFields: /* @__PURE__ */ new Set(),
15315
+ matchedAnchors: /* @__PURE__ */ new Map()
15316
+ };
15317
+ existing.anchorScore += score;
15318
+ existing.matchedFields.add("anchor");
15319
+ for (const field of matchedFields) existing.matchedFields.add(field);
15320
+ existing.matchedAnchors.set(anchor.anchorId, {
15321
+ anchorId: anchor.anchorId,
15322
+ anchorType: anchor.anchorType,
15323
+ anchorValue: anchor.anchorValue
15324
+ });
15325
+ candidates.set(nodeRef, existing);
15326
+ }
15327
+ }
15328
+ }
15329
+ return [...candidates.values()].map((candidate) => {
15330
+ let score = candidate.nodeScore + candidate.anchorScore;
15331
+ if (options.sessionKey && candidate.node.sessionKey === options.sessionKey) score += 0.5;
15332
+ return {
15333
+ node: candidate.node,
15334
+ score,
15335
+ nodeScore: candidate.nodeScore,
15336
+ anchorScore: candidate.anchorScore,
15337
+ matchedFields: [...candidate.matchedFields].sort(),
15338
+ matchedAnchors: [...candidate.matchedAnchors.values()].sort(
15339
+ (left, right) => left.anchorType.localeCompare(right.anchorType) || left.anchorValue.localeCompare(right.anchorValue)
15340
+ )
15341
+ };
15342
+ }).filter((result) => result.nodeScore > 0 || result.anchorScore > 0).sort(
15343
+ (left, right) => right.score - left.score || right.anchorScore - left.anchorScore || right.node.recordedAt.localeCompare(left.node.recordedAt)
15344
+ ).slice(0, options.maxResults);
15345
+ }
15346
+
15347
+ // src/verified-recall.ts
15348
+ function createReadOnlyBoxBuilder(memoryDir) {
15349
+ return new BoxBuilder(memoryDir, {
15350
+ memoryBoxesEnabled: true,
15351
+ traceWeaverEnabled: false,
15352
+ boxTopicShiftThreshold: 0.35,
15353
+ boxTimeGapMs: 30 * 60 * 1e3,
15354
+ boxMaxMemories: 50,
15355
+ traceWeaverLookbackDays: 7,
15356
+ traceWeaverOverlapThreshold: 0.4
15357
+ });
15358
+ }
15359
+ function scoreVerifiedEpisodeCandidate(box, verifiedMemories, queryTokens) {
15360
+ const matchedFields = /* @__PURE__ */ new Set();
15361
+ let score = 0;
15362
+ const topicMatches = countRecallTokenOverlap(queryTokens, box.topics.join(" "));
15363
+ if (topicMatches > 0) {
15364
+ score += topicMatches * 3;
15365
+ matchedFields.add("topics");
15366
+ }
15367
+ const goalMatches = countRecallTokenOverlap(queryTokens, box.goal);
15368
+ if (goalMatches > 0) {
15369
+ score += goalMatches * 4;
15370
+ matchedFields.add("goal");
15371
+ }
15372
+ const toolMatches = countRecallTokenOverlap(queryTokens, box.toolsUsed?.join(" "));
15373
+ if (toolMatches > 0) {
15374
+ score += toolMatches * 2;
15375
+ matchedFields.add("toolsUsed");
15376
+ }
15377
+ let episodeContentMatches = 0;
15378
+ for (const memory of verifiedMemories) {
15379
+ episodeContentMatches += countRecallTokenOverlap(queryTokens, memory.content);
15380
+ }
15381
+ if (episodeContentMatches > 0) {
15382
+ score += episodeContentMatches * 4;
15383
+ matchedFields.add("episodeContent");
15384
+ }
15385
+ return { score, matchedFields };
15386
+ }
15387
+ function resolveVerifiedEpisodeMemoriesFromMap(memoryById, memoryIds) {
15388
+ const verified = [];
15389
+ for (const memoryId of memoryIds) {
15390
+ try {
15391
+ const memory = memoryById.get(memoryId);
15392
+ if (!memory) continue;
15393
+ if (memory.frontmatter.status === "archived") continue;
15394
+ if (memory.frontmatter.memoryKind !== "episode") continue;
15395
+ verified.push(memory);
15396
+ } catch {
15397
+ }
15398
+ }
15399
+ return verified;
15400
+ }
15401
+ async function searchVerifiedEpisodes(options) {
15402
+ const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
15403
+ if (queryTokens.size === 0 || options.maxResults <= 0) return [];
15404
+ const storage = new StorageManager(options.memoryDir);
15405
+ const verifiedMemoryById = new Map(
15406
+ (await storage.readAllMemories()).filter((memory) => memory.frontmatter.status !== "archived").filter((memory) => memory.frontmatter.memoryKind === "episode").map((memory) => [memory.frontmatter.id, memory])
15407
+ );
15408
+ const boxes = await createReadOnlyBoxBuilder(options.memoryDir).readRecentBoxes(Math.max(1, Math.floor(options.boxRecallDays ?? 3))).catch(() => []);
15409
+ const candidates = [];
15410
+ for (const box of boxes) {
15411
+ const verifiedMemories = resolveVerifiedEpisodeMemoriesFromMap(verifiedMemoryById, box.memoryIds);
15412
+ if (verifiedMemories.length === 0) continue;
15413
+ const { score, matchedFields } = scoreVerifiedEpisodeCandidate(box, verifiedMemories, queryTokens);
15414
+ if (score <= 0) continue;
15415
+ candidates.push({
15416
+ box,
15417
+ score,
15418
+ matchedFields,
15419
+ verifiedMemories
15420
+ });
15421
+ }
15422
+ return candidates.map((candidate) => ({
15423
+ box: candidate.box,
15424
+ score: candidate.score,
15425
+ verifiedEpisodeCount: candidate.verifiedMemories.length,
15426
+ verifiedMemoryIds: candidate.verifiedMemories.map((memory) => memory.frontmatter.id),
15427
+ matchedFields: [...candidate.matchedFields].sort()
15428
+ })).sort(
15429
+ (left, right) => right.score - left.score || right.verifiedEpisodeCount - left.verifiedEpisodeCount || right.box.sealedAt.localeCompare(left.box.sealedAt)
15430
+ ).slice(0, options.maxResults);
15431
+ }
15432
+
15024
15433
  // src/replay/types.ts
15025
15434
  var VALID_SOURCES = /* @__PURE__ */ new Set(["openclaw", "claude", "chatgpt"]);
15026
15435
  var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant"]);
@@ -15129,8 +15538,8 @@ function chunkTranscriptEntries(sessionKey, entries, opts) {
15129
15538
  }
15130
15539
 
15131
15540
  // src/conversation-index/indexer.ts
15132
- import { mkdir as mkdir18, writeFile as writeFile19 } from "fs/promises";
15133
- import path25 from "path";
15541
+ import { mkdir as mkdir20, writeFile as writeFile21 } from "fs/promises";
15542
+ import path28 from "path";
15134
15543
  function sanitizeSessionKey(sessionKey) {
15135
15544
  const raw = typeof sessionKey === "string" && sessionKey.trim().length > 0 ? sessionKey : "unknown-session";
15136
15545
  return raw.toLowerCase().replace(/[^a-z0-9._-]+/g, "_").slice(0, 200);
@@ -15140,9 +15549,9 @@ async function writeConversationChunks(rootDir, chunks) {
15140
15549
  for (const c of chunks) {
15141
15550
  const safe = sanitizeSessionKey(c.sessionKey);
15142
15551
  const date = c.startTs.slice(0, 10);
15143
- const dir = path25.join(rootDir, safe, date);
15144
- await mkdir18(dir, { recursive: true });
15145
- const fp = path25.join(dir, `${c.id}.md`);
15552
+ const dir = path28.join(rootDir, safe, date);
15553
+ await mkdir20(dir, { recursive: true });
15554
+ const fp = path28.join(dir, `${c.id}.md`);
15146
15555
  const content = `---
15147
15556
  kind: conversation_chunk
15148
15557
  sessionKey: ${c.sessionKey}
@@ -15151,7 +15560,7 @@ endTs: ${c.endTs}
15151
15560
  ---
15152
15561
 
15153
15562
  ` + c.text + "\n";
15154
- await writeFile19(fp, content, "utf-8");
15563
+ await writeFile21(fp, content, "utf-8");
15155
15564
  written.push(fp);
15156
15565
  }
15157
15566
  return written;
@@ -15171,7 +15580,7 @@ async function upsertConversationChunksFailOpen(adapter, chunks) {
15171
15580
 
15172
15581
  // src/conversation-index/cleanup.ts
15173
15582
  import { readdir as readdir13, rm as rm2 } from "fs/promises";
15174
- import path26 from "path";
15583
+ import path29 from "path";
15175
15584
  async function cleanupConversationChunks(rootDir, retentionDays) {
15176
15585
  if (!Number.isFinite(retentionDays) || retentionDays <= 0) return;
15177
15586
  const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
@@ -15179,7 +15588,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
15179
15588
  const sessions = await readdir13(rootDir, { withFileTypes: true });
15180
15589
  for (const s of sessions) {
15181
15590
  if (!s.isDirectory()) continue;
15182
- const sessionDir = path26.join(rootDir, s.name);
15591
+ const sessionDir = path29.join(rootDir, s.name);
15183
15592
  const dayDirs = await readdir13(sessionDir, { withFileTypes: true });
15184
15593
  for (const d of dayDirs) {
15185
15594
  if (!d.isDirectory()) continue;
@@ -15187,7 +15596,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
15187
15596
  const dayMs = (/* @__PURE__ */ new Date(d.name + "T00:00:00.000Z")).getTime();
15188
15597
  if (!Number.isFinite(dayMs)) continue;
15189
15598
  if (dayMs < cutoffMs) {
15190
- await rm2(path26.join(sessionDir, d.name), { recursive: true, force: true });
15599
+ await rm2(path29.join(sessionDir, d.name), { recursive: true, force: true });
15191
15600
  }
15192
15601
  }
15193
15602
  try {
@@ -15206,7 +15615,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
15206
15615
  // src/conversation-index/faiss-adapter.ts
15207
15616
  import * as childProcess from "child_process";
15208
15617
  import { fileURLToPath } from "url";
15209
- import path27 from "path";
15618
+ import path30 from "path";
15210
15619
  var FaissAdapterError = class extends Error {
15211
15620
  constructor(message, code) {
15212
15621
  super(message);
@@ -15216,18 +15625,18 @@ var FaissAdapterError = class extends Error {
15216
15625
  };
15217
15626
  function resolveDefaultFaissScriptPath(fromModuleUrl = import.meta.url) {
15218
15627
  const currentFile = fileURLToPath(fromModuleUrl);
15219
- const moduleDir = path27.dirname(currentFile);
15220
- if (moduleDir.endsWith(`${path27.sep}conversation-index`)) {
15221
- return path27.resolve(moduleDir, "..", "..", "scripts", "faiss_index.py");
15628
+ const moduleDir = path30.dirname(currentFile);
15629
+ if (moduleDir.endsWith(`${path30.sep}conversation-index`)) {
15630
+ return path30.resolve(moduleDir, "..", "..", "scripts", "faiss_index.py");
15222
15631
  }
15223
- return path27.resolve(moduleDir, "..", "scripts", "faiss_index.py");
15632
+ return path30.resolve(moduleDir, "..", "scripts", "faiss_index.py");
15224
15633
  }
15225
15634
  var FaissConversationIndexAdapter = class {
15226
15635
  constructor(config) {
15227
15636
  this.config = config;
15228
15637
  this.pythonBin = config.pythonBin && config.pythonBin.trim().length > 0 ? config.pythonBin.trim() : "python3";
15229
15638
  this.scriptPath = config.scriptPath && config.scriptPath.trim().length > 0 ? config.scriptPath.trim() : resolveDefaultFaissScriptPath();
15230
- this.indexPath = path27.isAbsolute(config.indexDir) ? config.indexDir : path27.join(config.memoryDir, config.indexDir);
15639
+ this.indexPath = path30.isAbsolute(config.indexDir) ? config.indexDir : path30.join(config.memoryDir, config.indexDir);
15231
15640
  this.spawnFn = config.spawnFn ?? childProcess.spawn;
15232
15641
  }
15233
15642
  pythonBin;
@@ -15408,7 +15817,7 @@ async function searchConversationIndexFaissFailOpen(adapter, query, maxResults)
15408
15817
  }
15409
15818
 
15410
15819
  // src/namespaces/storage.ts
15411
- import path28 from "path";
15820
+ import path31 from "path";
15412
15821
  import { access } from "fs/promises";
15413
15822
  async function exists(p) {
15414
15823
  try {
@@ -15430,7 +15839,7 @@ var NamespaceStorageRouter = class {
15430
15839
  this.defaultNsRootResolved = this.config.memoryDir;
15431
15840
  return this.defaultNsRootResolved;
15432
15841
  }
15433
- const nsDir = path28.join(this.config.memoryDir, "namespaces", this.config.defaultNamespace);
15842
+ const nsDir = path31.join(this.config.memoryDir, "namespaces", this.config.defaultNamespace);
15434
15843
  this.defaultNsRootResolved = await exists(nsDir) ? nsDir : this.config.memoryDir;
15435
15844
  return this.defaultNsRootResolved;
15436
15845
  }
@@ -15439,7 +15848,7 @@ var NamespaceStorageRouter = class {
15439
15848
  if (namespace === this.config.defaultNamespace) {
15440
15849
  return this.defaultNsRootResolved ?? this.config.memoryDir;
15441
15850
  }
15442
- return path28.join(this.config.memoryDir, "namespaces", namespace);
15851
+ return path31.join(this.config.memoryDir, "namespaces", namespace);
15443
15852
  }
15444
15853
  async storageFor(namespace) {
15445
15854
  const ns = namespace || this.config.defaultNamespace;
@@ -15515,8 +15924,8 @@ function recallNamespacesForPrincipal(principal, config) {
15515
15924
  }
15516
15925
 
15517
15926
  // src/shared-context/manager.ts
15518
- import { mkdir as mkdir19, readFile as readFile19, readdir as readdir14, appendFile as appendFile4, writeFile as writeFile20, stat as stat5 } from "fs/promises";
15519
- import path29 from "path";
15927
+ import { mkdir as mkdir21, readFile as readFile19, readdir as readdir14, appendFile as appendFile4, writeFile as writeFile22, stat as stat5 } from "fs/promises";
15928
+ import path32 from "path";
15520
15929
  import os3 from "os";
15521
15930
  import { z as z3 } from "zod";
15522
15931
  var SharedFeedbackEntrySchema = z3.object({
@@ -15712,15 +16121,15 @@ async function computeSemanticOverlapsWithTimeout(sources, timeoutMs, maxCandida
15712
16121
  var SharedContextManager = class {
15713
16122
  constructor(config) {
15714
16123
  this.config = config;
15715
- const base = typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0 ? config.sharedContextDir : path29.join(os3.homedir(), ".openclaw", "workspace", "shared-context");
16124
+ const base = typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0 ? config.sharedContextDir : path32.join(os3.homedir(), ".openclaw", "workspace", "shared-context");
15716
16125
  this.dir = base;
15717
- this.prioritiesPath = path29.join(base, "priorities.md");
15718
- this.prioritiesInboxPath = path29.join(base, "priorities.inbox.md");
15719
- this.outputsDir = path29.join(base, "agent-outputs");
15720
- this.roundtableDir = path29.join(base, "roundtable");
15721
- this.feedbackDir = path29.join(base, "feedback");
15722
- this.feedbackInboxPath = path29.join(this.feedbackDir, "inbox.jsonl");
15723
- this.crossSignalsDir = path29.join(base, "cross-signals");
16126
+ this.prioritiesPath = path32.join(base, "priorities.md");
16127
+ this.prioritiesInboxPath = path32.join(base, "priorities.inbox.md");
16128
+ this.outputsDir = path32.join(base, "agent-outputs");
16129
+ this.roundtableDir = path32.join(base, "roundtable");
16130
+ this.feedbackDir = path32.join(base, "feedback");
16131
+ this.feedbackInboxPath = path32.join(this.feedbackDir, "inbox.jsonl");
16132
+ this.crossSignalsDir = path32.join(base, "cross-signals");
15724
16133
  }
15725
16134
  dir;
15726
16135
  prioritiesPath;
@@ -15731,15 +16140,15 @@ var SharedContextManager = class {
15731
16140
  feedbackInboxPath;
15732
16141
  crossSignalsDir;
15733
16142
  async ensureStructure() {
15734
- await mkdir19(this.dir, { recursive: true });
15735
- await mkdir19(this.outputsDir, { recursive: true });
15736
- await mkdir19(this.roundtableDir, { recursive: true });
15737
- await mkdir19(this.feedbackDir, { recursive: true });
15738
- await mkdir19(this.crossSignalsDir, { recursive: true });
15739
- await mkdir19(path29.join(this.dir, "staging"), { recursive: true });
15740
- await mkdir19(path29.join(this.dir, "kpis"), { recursive: true });
15741
- await mkdir19(path29.join(this.dir, "calendar"), { recursive: true });
15742
- await mkdir19(path29.join(this.dir, "content-calendar"), { recursive: true });
16143
+ await mkdir21(this.dir, { recursive: true });
16144
+ await mkdir21(this.outputsDir, { recursive: true });
16145
+ await mkdir21(this.roundtableDir, { recursive: true });
16146
+ await mkdir21(this.feedbackDir, { recursive: true });
16147
+ await mkdir21(this.crossSignalsDir, { recursive: true });
16148
+ await mkdir21(path32.join(this.dir, "staging"), { recursive: true });
16149
+ await mkdir21(path32.join(this.dir, "kpis"), { recursive: true });
16150
+ await mkdir21(path32.join(this.dir, "calendar"), { recursive: true });
16151
+ await mkdir21(path32.join(this.dir, "content-calendar"), { recursive: true });
15743
16152
  await this.ensureFile(
15744
16153
  this.prioritiesPath,
15745
16154
  [
@@ -15770,7 +16179,7 @@ var SharedContextManager = class {
15770
16179
  try {
15771
16180
  await stat5(fp);
15772
16181
  } catch {
15773
- await writeFile20(fp, content, "utf-8");
16182
+ await writeFile22(fp, content, "utf-8");
15774
16183
  }
15775
16184
  }
15776
16185
  async readPriorities() {
@@ -15783,7 +16192,7 @@ var SharedContextManager = class {
15783
16192
  async readLatestRoundtable() {
15784
16193
  try {
15785
16194
  const files = (await readdir14(this.roundtableDir)).filter((f) => f.endsWith(".md")).sort().reverse();
15786
- const fp = files[0] ? path29.join(this.roundtableDir, files[0]) : null;
16195
+ const fp = files[0] ? path32.join(this.roundtableDir, files[0]) : null;
15787
16196
  if (!fp) return "";
15788
16197
  return await readFile19(fp, "utf-8");
15789
16198
  } catch {
@@ -15795,9 +16204,9 @@ var SharedContextManager = class {
15795
16204
  const date = ymd(createdAt);
15796
16205
  const time = createdAt.toISOString().slice(11, 19).replace(/:/g, "");
15797
16206
  const slug = safeSlug(opts.title);
15798
- const dir = path29.join(this.outputsDir, opts.agentId, date);
15799
- await mkdir19(dir, { recursive: true });
15800
- const fp = path29.join(dir, `${time}-${slug}.md`);
16207
+ const dir = path32.join(this.outputsDir, opts.agentId, date);
16208
+ await mkdir21(dir, { recursive: true });
16209
+ const fp = path32.join(dir, `${time}-${slug}.md`);
15801
16210
  const body = `---
15802
16211
  kind: agent_output
15803
16212
  agent: ${opts.agentId}
@@ -15806,7 +16215,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
15806
16215
  ---
15807
16216
 
15808
16217
  ` + opts.content.trimEnd() + "\n";
15809
- await writeFile20(fp, body, "utf-8");
16218
+ await writeFile22(fp, body, "utf-8");
15810
16219
  return fp;
15811
16220
  }
15812
16221
  async appendFeedback(entry) {
@@ -15832,11 +16241,11 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
15832
16241
  const agents = await readdir14(this.outputsDir, { withFileTypes: true });
15833
16242
  for (const a of agents) {
15834
16243
  if (!a.isDirectory()) continue;
15835
- const dayDir = path29.join(this.outputsDir, a.name, date);
16244
+ const dayDir = path32.join(this.outputsDir, a.name, date);
15836
16245
  try {
15837
16246
  const files = (await readdir14(dayDir)).filter((f) => f.endsWith(".md")).sort();
15838
16247
  for (const f of files) {
15839
- const p = path29.join(dayDir, f);
16248
+ const p = path32.join(dayDir, f);
15840
16249
  const raw = await readFile19(p, "utf-8");
15841
16250
  const title = (raw.match(/^title:\s*(.+)$/m)?.[1] ?? f).trim();
15842
16251
  outputs.push({ agent: a.name, path: p, title, raw });
@@ -15943,8 +16352,8 @@ ${body}`)
15943
16352
  addedOverlapCount: semanticAddedOverlapCount
15944
16353
  }
15945
16354
  };
15946
- const crossSignalsPath = path29.join(this.crossSignalsDir, `${date}.json`);
15947
- await writeFile20(crossSignalsPath, `${JSON.stringify(crossSignalReport, null, 2)}
16355
+ const crossSignalsPath = path32.join(this.crossSignalsDir, `${date}.json`);
16356
+ await writeFile22(crossSignalsPath, `${JSON.stringify(crossSignalReport, null, 2)}
15948
16357
  `, "utf-8");
15949
16358
  const overlapBullets = mergedOverlaps.length === 0 ? ["- No multi-agent topic overlap detected."] : mergedOverlaps.slice(0, 8).map((entry) => `- \`${entry.token}\` (${entry.agentCount} agents: ${entry.agents.join(", ")})`);
15950
16359
  const md = [
@@ -15967,8 +16376,8 @@ ${body}`)
15967
16376
  ];
15968
16377
  const out = md.join("\n");
15969
16378
  const trimmed = out.length > maxChars ? out.slice(0, maxChars) + "\n\n...(trimmed)\n" : out;
15970
- const roundtablePath = path29.join(this.roundtableDir, `${date}.md`);
15971
- await writeFile20(roundtablePath, trimmed, "utf-8");
16379
+ const roundtablePath = path32.join(this.roundtableDir, `${date}.md`);
16380
+ await writeFile22(roundtablePath, trimmed, "utf-8");
15972
16381
  log.info(`shared-context curated daily roundtable: ${roundtablePath}`);
15973
16382
  return {
15974
16383
  date,
@@ -15980,8 +16389,8 @@ ${body}`)
15980
16389
  };
15981
16390
 
15982
16391
  // src/compounding/engine.ts
15983
- import { mkdir as mkdir20, readFile as readFile20, readdir as readdir15, writeFile as writeFile21 } from "fs/promises";
15984
- import path30 from "path";
16392
+ import { mkdir as mkdir22, readFile as readFile20, readdir as readdir15, writeFile as writeFile23 } from "fs/promises";
16393
+ import path33 from "path";
15985
16394
  import os4 from "os";
15986
16395
  function defaultTierMigrationCycleBudget(config, trigger) {
15987
16396
  if (trigger === "extraction") {
@@ -16028,7 +16437,7 @@ function sharedContextDir(config) {
16028
16437
  if (typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0) {
16029
16438
  return config.sharedContextDir;
16030
16439
  }
16031
- return path30.join(os4.homedir(), ".openclaw", "workspace", "shared-context");
16440
+ return path33.join(os4.homedir(), ".openclaw", "workspace", "shared-context");
16032
16441
  }
16033
16442
  function cadenceStaleWindowMs(cadence) {
16034
16443
  switch (cadence) {
@@ -16047,16 +16456,16 @@ function cadenceStaleWindowMs(cadence) {
16047
16456
  var CompoundingEngine = class {
16048
16457
  constructor(config) {
16049
16458
  this.config = config;
16050
- this.weeklyDir = path30.join(config.memoryDir, "compounding", "weekly");
16051
- this.rubricsPath = path30.join(config.memoryDir, "compounding", "rubrics.md");
16052
- this.mistakesPath = path30.join(config.memoryDir, "compounding", "mistakes.json");
16053
- this.feedbackInboxPath = path30.join(sharedContextDir(config), "feedback", "inbox.jsonl");
16054
- this.identityAnchorPath = path30.join(config.memoryDir, "identity", "identity-anchor.md");
16055
- this.identityIncidentsDir = path30.join(config.memoryDir, "identity", "incidents");
16056
- this.identityAuditWeeklyDir = path30.join(config.memoryDir, "identity", "audits", "weekly");
16057
- this.identityAuditMonthlyDir = path30.join(config.memoryDir, "identity", "audits", "monthly");
16058
- this.identityImprovementLoopsPath = path30.join(config.memoryDir, "identity", "improvement-loops.md");
16059
- this.memoryActionEventsPath = path30.join(config.memoryDir, "state", "memory-actions.jsonl");
16459
+ this.weeklyDir = path33.join(config.memoryDir, "compounding", "weekly");
16460
+ this.rubricsPath = path33.join(config.memoryDir, "compounding", "rubrics.md");
16461
+ this.mistakesPath = path33.join(config.memoryDir, "compounding", "mistakes.json");
16462
+ this.feedbackInboxPath = path33.join(sharedContextDir(config), "feedback", "inbox.jsonl");
16463
+ this.identityAnchorPath = path33.join(config.memoryDir, "identity", "identity-anchor.md");
16464
+ this.identityIncidentsDir = path33.join(config.memoryDir, "identity", "incidents");
16465
+ this.identityAuditWeeklyDir = path33.join(config.memoryDir, "identity", "audits", "weekly");
16466
+ this.identityAuditMonthlyDir = path33.join(config.memoryDir, "identity", "audits", "monthly");
16467
+ this.identityImprovementLoopsPath = path33.join(config.memoryDir, "identity", "improvement-loops.md");
16468
+ this.memoryActionEventsPath = path33.join(config.memoryDir, "state", "memory-actions.jsonl");
16060
16469
  }
16061
16470
  weeklyDir;
16062
16471
  rubricsPath;
@@ -16069,9 +16478,9 @@ var CompoundingEngine = class {
16069
16478
  identityImprovementLoopsPath;
16070
16479
  memoryActionEventsPath;
16071
16480
  async ensureDirs() {
16072
- await mkdir20(this.weeklyDir, { recursive: true });
16073
- await mkdir20(path30.dirname(this.mistakesPath), { recursive: true });
16074
- await mkdir20(path30.dirname(this.rubricsPath), { recursive: true });
16481
+ await mkdir22(this.weeklyDir, { recursive: true });
16482
+ await mkdir22(path33.dirname(this.mistakesPath), { recursive: true });
16483
+ await mkdir22(path33.dirname(this.rubricsPath), { recursive: true });
16075
16484
  }
16076
16485
  async synthesizeWeekly(opts) {
16077
16486
  await this.ensureDirs();
@@ -16082,12 +16491,12 @@ var CompoundingEngine = class {
16082
16491
  const promotionCandidates = this.config.compoundingSemanticEnabled ? this.derivePromotionCandidates(outcomeSummary) : [];
16083
16492
  const mistakes = this.buildMistakes(entries, actionPatterns);
16084
16493
  const continuity = this.config.continuityAuditEnabled ? await this.readContinuityAuditReferences(weekId) : { monthId: monthIdFromIsoWeek(weekId), weeklyPath: null, monthlyPath: null };
16085
- const reportPath = path30.join(this.weeklyDir, `${weekId}.md`);
16494
+ const reportPath = path33.join(this.weeklyDir, `${weekId}.md`);
16086
16495
  const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns, mistakes.details, continuity, outcomeSummary, promotionCandidates);
16087
- await writeFile21(reportPath, md, "utf-8");
16496
+ await writeFile23(reportPath, md, "utf-8");
16088
16497
  const rubrics = this.formatRubrics(entries, outcomeSummary);
16089
- await writeFile21(this.rubricsPath, rubrics, "utf-8");
16090
- await writeFile21(
16498
+ await writeFile23(this.rubricsPath, rubrics, "utf-8");
16499
+ await writeFile23(
16091
16500
  this.mistakesPath,
16092
16501
  JSON.stringify({ updatedAt: mistakes.updatedAt, patterns: mistakes.patterns }, null, 2) + "\n",
16093
16502
  "utf-8"
@@ -16167,9 +16576,9 @@ var CompoundingEngine = class {
16167
16576
  ""
16168
16577
  ];
16169
16578
  const dir = period === "weekly" ? this.identityAuditWeeklyDir : this.identityAuditMonthlyDir;
16170
- await mkdir20(dir, { recursive: true });
16171
- const reportPath = path30.join(dir, `${key}.md`);
16172
- await writeFile21(reportPath, lines.join("\n"), "utf-8");
16579
+ await mkdir22(dir, { recursive: true });
16580
+ const reportPath = path33.join(dir, `${key}.md`);
16581
+ await writeFile23(reportPath, lines.join("\n"), "utf-8");
16173
16582
  return { period, key, reportPath };
16174
16583
  }
16175
16584
  async readMistakes() {
@@ -16268,7 +16677,7 @@ var CompoundingEngine = class {
16268
16677
  else if (event.outcome === "skipped") acc.counts.skipped += 1;
16269
16678
  else if (event.outcome === "failed") acc.counts.failed += 1;
16270
16679
  else acc.counts.unknown += 1;
16271
- acc.provenance.add(`${path30.basename(this.memoryActionEventsPath)}:L${event.line}`);
16680
+ acc.provenance.add(`${path33.basename(this.memoryActionEventsPath)}:L${event.line}`);
16272
16681
  byAction.set(key, acc);
16273
16682
  }
16274
16683
  const out = [];
@@ -16306,7 +16715,7 @@ var CompoundingEngine = class {
16306
16715
  const patterns = [];
16307
16716
  for (const wrapped of entries) {
16308
16717
  const e = wrapped.entry;
16309
- const provenance = [`${path30.basename(wrapped.sourcePath)}:L${wrapped.sourceLine}#${wrapped.entryId}`];
16718
+ const provenance = [`${path33.basename(wrapped.sourcePath)}:L${wrapped.sourceLine}#${wrapped.entryId}`];
16310
16719
  if (e.learning && e.learning.trim().length > 0) {
16311
16720
  patterns.push({ pattern: `${e.agent}: ${e.learning.trim()}`, provenance });
16312
16721
  continue;
@@ -16316,7 +16725,7 @@ var CompoundingEngine = class {
16316
16725
  }
16317
16726
  }
16318
16727
  for (const p of actionPatterns) {
16319
- patterns.push({ pattern: p, provenance: [`${path30.basename(this.memoryActionEventsPath)}:*`] });
16728
+ patterns.push({ pattern: p, provenance: [`${path33.basename(this.memoryActionEventsPath)}:*`] });
16320
16729
  }
16321
16730
  const byPattern = /* @__PURE__ */ new Map();
16322
16731
  for (const p of patterns) {
@@ -16356,7 +16765,7 @@ var CompoundingEngine = class {
16356
16765
  lines.push(`- approved: ${approved}`);
16357
16766
  lines.push(`- approved_with_feedback: ${awf}`);
16358
16767
  lines.push(`- rejected: ${rejected}`);
16359
- const provenance = list.slice(0, 3).map((e) => `${path30.basename(e.sourcePath)}:L${e.sourceLine}#${e.entryId}`);
16768
+ const provenance = list.slice(0, 3).map((e) => `${path33.basename(e.sourcePath)}:L${e.sourceLine}#${e.entryId}`);
16360
16769
  if (provenance.length > 0) {
16361
16770
  lines.push(`- provenance: ${provenance.join(", ")}`);
16362
16771
  }
@@ -16447,7 +16856,7 @@ var CompoundingEngine = class {
16447
16856
  } else {
16448
16857
  for (const item of learnings) {
16449
16858
  const note = (item.entry.learning && item.entry.learning.trim().length > 0 ? item.entry.learning : item.entry.reason).trim();
16450
- lines.push(`- ${note} _(source: ${path30.basename(item.sourcePath)}:L${item.sourceLine}#${item.entryId})_`);
16859
+ lines.push(`- ${note} _(source: ${path33.basename(item.sourcePath)}:L${item.sourceLine}#${item.entryId})_`);
16451
16860
  }
16452
16861
  }
16453
16862
  lines.push("");
@@ -16492,7 +16901,7 @@ var CompoundingEngine = class {
16492
16901
  const files = names.filter((n) => n.endsWith(".md")).sort().reverse();
16493
16902
  for (const file of files) {
16494
16903
  if (incidents.length >= cappedLimit) break;
16495
- const filePath = path30.join(this.identityIncidentsDir, file);
16904
+ const filePath = path33.join(this.identityIncidentsDir, file);
16496
16905
  try {
16497
16906
  const raw = await readFile20(filePath, "utf-8");
16498
16907
  const parsed = parseContinuityIncident(raw);
@@ -16508,8 +16917,8 @@ var CompoundingEngine = class {
16508
16917
  }
16509
16918
  async readContinuityAuditReferences(weekId) {
16510
16919
  const monthId = monthIdFromIsoWeek(weekId);
16511
- const weeklyPath = path30.join(this.identityAuditWeeklyDir, `${weekId}.md`);
16512
- const monthlyPath = path30.join(this.identityAuditMonthlyDir, `${monthId}.md`);
16920
+ const weeklyPath = path33.join(this.identityAuditWeeklyDir, `${weekId}.md`);
16921
+ const monthlyPath = path33.join(this.identityAuditMonthlyDir, `${monthId}.md`);
16513
16922
  const weeklyExists = await this.readNonEmptyFile(weeklyPath);
16514
16923
  const monthlyExists = await this.readNonEmptyFile(monthlyPath);
16515
16924
  return {
@@ -16522,8 +16931,8 @@ var CompoundingEngine = class {
16522
16931
  };
16523
16932
 
16524
16933
  // src/tier-migration.ts
16525
- import { appendFile as appendFile5, mkdir as mkdir21 } from "fs/promises";
16526
- import path31 from "path";
16934
+ import { appendFile as appendFile5, mkdir as mkdir23 } from "fs/promises";
16935
+ import path34 from "path";
16527
16936
  var TierMigrationExecutor = class {
16528
16937
  storage;
16529
16938
  qmd;
@@ -16537,7 +16946,7 @@ var TierMigrationExecutor = class {
16537
16946
  this.hotCollection = options.hotCollection;
16538
16947
  this.coldCollection = options.coldCollection;
16539
16948
  this.autoEmbed = options.autoEmbed === true;
16540
- this.journalPath = options.journalPath ?? path31.join(this.storage.dir, "state", "tier-migration-journal.jsonl");
16949
+ this.journalPath = options.journalPath ?? path34.join(this.storage.dir, "state", "tier-migration-journal.jsonl");
16541
16950
  }
16542
16951
  async migrateMemory(request) {
16543
16952
  const { memory, fromTier, toTier, reason } = request;
@@ -16590,7 +16999,7 @@ var TierMigrationExecutor = class {
16590
16999
  reason: result.reason,
16591
17000
  targetPath: result.targetPath
16592
17001
  };
16593
- await mkdir21(path31.dirname(this.journalPath), { recursive: true });
17002
+ await mkdir23(path34.dirname(this.journalPath), { recursive: true });
16594
17003
  await appendFile5(this.journalPath, `${JSON.stringify(entry)}
16595
17004
  `, "utf-8");
16596
17005
  }
@@ -16757,8 +17166,8 @@ function selectRouteRule(text, rules, options) {
16757
17166
  }
16758
17167
 
16759
17168
  // src/routing/store.ts
16760
- import { lstat, mkdir as mkdir22, readFile as readFile21, realpath, rename as rename2, rm as rm3, stat as stat6, writeFile as writeFile22 } from "fs/promises";
16761
- import path32 from "path";
17169
+ import { lstat, mkdir as mkdir24, readFile as readFile21, realpath, rename as rename2, rm as rm3, stat as stat6, writeFile as writeFile24 } from "fs/promises";
17170
+ import path35 from "path";
16762
17171
  import { createHash as createHash4 } from "crypto";
16763
17172
  function defaultState() {
16764
17173
  return {
@@ -16777,14 +17186,14 @@ function stableRuleId(rule) {
16777
17186
  return `route-${createHash4("sha256").update(seed).digest("hex").slice(0, 12)}`;
16778
17187
  }
16779
17188
  function resolveStatePath(memoryDir, stateFile) {
16780
- const root = path32.resolve(memoryDir);
16781
- const defaultPath = path32.join(root, "state", "routing-rules.json");
16782
- if (path32.isAbsolute(stateFile)) {
16783
- const absolute = path32.resolve(stateFile);
16784
- return absolute.startsWith(root + path32.sep) ? absolute : defaultPath;
17189
+ const root = path35.resolve(memoryDir);
17190
+ const defaultPath = path35.join(root, "state", "routing-rules.json");
17191
+ if (path35.isAbsolute(stateFile)) {
17192
+ const absolute = path35.resolve(stateFile);
17193
+ return absolute.startsWith(root + path35.sep) ? absolute : defaultPath;
16785
17194
  }
16786
- const resolved = path32.resolve(root, stateFile);
16787
- return resolved.startsWith(root + path32.sep) ? resolved : defaultPath;
17195
+ const resolved = path35.resolve(root, stateFile);
17196
+ return resolved.startsWith(root + path35.sep) ? resolved : defaultPath;
16788
17197
  }
16789
17198
  function normalizeRule(rule, options) {
16790
17199
  if (!rule || typeof rule !== "object") return null;
@@ -16817,7 +17226,7 @@ var RoutingRulesStore = class {
16817
17226
  lockPath;
16818
17227
  writeQueue = Promise.resolve();
16819
17228
  constructor(memoryDir, stateFile = "state/routing-rules.json") {
16820
- this.memoryRoot = path32.resolve(memoryDir);
17229
+ this.memoryRoot = path35.resolve(memoryDir);
16821
17230
  this.statePath = resolveStatePath(memoryDir, stateFile);
16822
17231
  this.lockPath = `${this.statePath}.lock`;
16823
17232
  }
@@ -16855,7 +17264,7 @@ var RoutingRulesStore = class {
16855
17264
  await this.withWriteLock(async () => {
16856
17265
  const payload = defaultState();
16857
17266
  await this.assertStatePathScoped();
16858
- await writeFile22(this.statePath, JSON.stringify(payload, null, 2), "utf-8");
17267
+ await writeFile24(this.statePath, JSON.stringify(payload, null, 2), "utf-8");
16859
17268
  });
16860
17269
  }
16861
17270
  dedupeById(rules) {
@@ -16889,7 +17298,7 @@ var RoutingRulesStore = class {
16889
17298
  const tmpPath = `${this.statePath}.tmp-${process.pid}-${Date.now()}`;
16890
17299
  try {
16891
17300
  await this.assertStatePathScoped();
16892
- await writeFile22(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
17301
+ await writeFile24(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
16893
17302
  await rename2(tmpPath, this.statePath);
16894
17303
  } catch (err) {
16895
17304
  log.debug(`routing rules write failed: ${err}`);
@@ -16923,10 +17332,10 @@ var RoutingRulesStore = class {
16923
17332
  const timeoutMs = 5e3;
16924
17333
  let unexpectedLockError = null;
16925
17334
  await this.assertStatePathScoped();
16926
- await mkdir22(path32.dirname(this.lockPath), { recursive: true });
17335
+ await mkdir24(path35.dirname(this.lockPath), { recursive: true });
16927
17336
  while (Date.now() - start < timeoutMs) {
16928
17337
  try {
16929
- await mkdir22(this.lockPath);
17338
+ await mkdir24(this.lockPath);
16930
17339
  return async () => {
16931
17340
  try {
16932
17341
  await rm3(this.lockPath, { recursive: true, force: true });
@@ -16956,14 +17365,14 @@ var RoutingRulesStore = class {
16956
17365
  throw new Error(`routing rules lock acquisition timed out after ${timeoutMs}ms`);
16957
17366
  }
16958
17367
  async assertStatePathScoped() {
16959
- await mkdir22(this.memoryRoot, { recursive: true });
17368
+ await mkdir24(this.memoryRoot, { recursive: true });
16960
17369
  const canonicalRoot = await realpath(this.memoryRoot);
16961
- const canonicalParent = await this.canonicalizePathWithoutCreating(path32.dirname(this.statePath));
16962
- const canonicalStatePath = path32.join(canonicalParent, path32.basename(this.statePath));
17370
+ const canonicalParent = await this.canonicalizePathWithoutCreating(path35.dirname(this.statePath));
17371
+ const canonicalStatePath = path35.join(canonicalParent, path35.basename(this.statePath));
16963
17372
  if (!this.isPathInside(canonicalRoot, canonicalStatePath)) {
16964
17373
  throw new Error(`routing rules state path escaped memoryDir: ${canonicalStatePath}`);
16965
17374
  }
16966
- await mkdir22(path32.dirname(this.statePath), { recursive: true });
17375
+ await mkdir24(path35.dirname(this.statePath), { recursive: true });
16967
17376
  try {
16968
17377
  const stateStats = await lstat(this.statePath);
16969
17378
  if (stateStats.isSymbolicLink()) {
@@ -16980,28 +17389,28 @@ var RoutingRulesStore = class {
16980
17389
  }
16981
17390
  }
16982
17391
  isPathInside(root, candidate) {
16983
- const normalizedRoot = path32.resolve(root);
16984
- const normalizedCandidate = path32.resolve(candidate);
17392
+ const normalizedRoot = path35.resolve(root);
17393
+ const normalizedCandidate = path35.resolve(candidate);
16985
17394
  if (normalizedCandidate === normalizedRoot) return true;
16986
- if (normalizedRoot === path32.parse(normalizedRoot).root) {
17395
+ if (normalizedRoot === path35.parse(normalizedRoot).root) {
16987
17396
  return normalizedCandidate.startsWith(normalizedRoot);
16988
17397
  }
16989
- return normalizedCandidate.startsWith(`${normalizedRoot}${path32.sep}`);
17398
+ return normalizedCandidate.startsWith(`${normalizedRoot}${path35.sep}`);
16990
17399
  }
16991
17400
  async canonicalizePathWithoutCreating(targetPath) {
16992
- const absoluteTarget = path32.resolve(targetPath);
17401
+ const absoluteTarget = path35.resolve(targetPath);
16993
17402
  let probe = absoluteTarget;
16994
17403
  while (true) {
16995
17404
  try {
16996
17405
  const canonicalProbe = await realpath(probe);
16997
- const remainder = path32.relative(probe, absoluteTarget);
16998
- return path32.resolve(canonicalProbe, remainder);
17406
+ const remainder = path35.relative(probe, absoluteTarget);
17407
+ return path35.resolve(canonicalProbe, remainder);
16999
17408
  } catch (err) {
17000
17409
  const code = err.code;
17001
17410
  if (code !== "ENOENT") {
17002
17411
  throw err;
17003
17412
  }
17004
- const parent = path32.dirname(probe);
17413
+ const parent = path35.dirname(probe);
17005
17414
  if (parent === probe) {
17006
17415
  return absoluteTarget;
17007
17416
  }
@@ -17012,8 +17421,8 @@ var RoutingRulesStore = class {
17012
17421
  };
17013
17422
 
17014
17423
  // src/policy-runtime.ts
17015
- import path33 from "path";
17016
- import { mkdir as mkdir23, readFile as readFile22, rename as rename3, writeFile as writeFile23 } from "fs/promises";
17424
+ import path36 from "path";
17425
+ import { mkdir as mkdir25, readFile as readFile22, rename as rename3, writeFile as writeFile25 } from "fs/promises";
17017
17426
  var RUNTIME_POLICY_VERSION = 1;
17018
17427
  var RUNTIME_POLICY_FILE = "policy-runtime.json";
17019
17428
  var RUNTIME_POLICY_PREV_FILE = "policy-runtime.prev.json";
@@ -17061,8 +17470,8 @@ async function readRuntimePolicySnapshot(filePath, options) {
17061
17470
  }
17062
17471
  async function writeSnapshotAtomic(filePath, snapshot) {
17063
17472
  const tempPath = `${filePath}.tmp`;
17064
- await mkdir23(path33.dirname(filePath), { recursive: true });
17065
- await writeFile23(tempPath, `${JSON.stringify(snapshot, null, 2)}
17473
+ await mkdir25(path36.dirname(filePath), { recursive: true });
17474
+ await writeFile25(tempPath, `${JSON.stringify(snapshot, null, 2)}
17066
17475
  `, "utf-8");
17067
17476
  await rename3(tempPath, filePath);
17068
17477
  }
@@ -17070,9 +17479,9 @@ var PolicyRuntimeManager = class {
17070
17479
  constructor(memoryDir, config) {
17071
17480
  this.memoryDir = memoryDir;
17072
17481
  this.config = config;
17073
- const stateDir2 = path33.join(memoryDir, "state");
17074
- this.runtimePath = path33.join(stateDir2, RUNTIME_POLICY_FILE);
17075
- this.runtimePrevPath = path33.join(stateDir2, RUNTIME_POLICY_PREV_FILE);
17482
+ const stateDir2 = path36.join(memoryDir, "state");
17483
+ this.runtimePath = path36.join(stateDir2, RUNTIME_POLICY_FILE);
17484
+ this.runtimePrevPath = path36.join(stateDir2, RUNTIME_POLICY_PREV_FILE);
17076
17485
  }
17077
17486
  runtimePath;
17078
17487
  runtimePrevPath;
@@ -17225,7 +17634,7 @@ function dedupeBehaviorSignalsByMemoryAndHash(signals) {
17225
17634
  // src/orchestrator.ts
17226
17635
  var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
17227
17636
  function defaultWorkspaceDir() {
17228
- return path34.join(os5.homedir(), ".openclaw", "workspace");
17637
+ return path37.join(os5.homedir(), ".openclaw", "workspace");
17229
17638
  }
17230
17639
  function sanitizeSessionKeyForFilename(sessionKey) {
17231
17640
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -17365,11 +17774,11 @@ function mergeGraphExpandedResults(primary, expanded) {
17365
17774
  return Array.from(mergedByPath.values());
17366
17775
  }
17367
17776
  function graphPathRelativeToStorage(storageDir, candidatePath) {
17368
- const absolutePath = path34.isAbsolute(candidatePath) ? candidatePath : path34.resolve(storageDir, candidatePath);
17369
- const rel = path34.relative(storageDir, absolutePath);
17777
+ const absolutePath = path37.isAbsolute(candidatePath) ? candidatePath : path37.resolve(storageDir, candidatePath);
17778
+ const rel = path37.relative(storageDir, absolutePath);
17370
17779
  if (!rel || rel === ".") return null;
17371
17780
  if (rel.startsWith("..")) return null;
17372
- return rel.split(path34.sep).join("/");
17781
+ return rel.split(path37.sep).join("/");
17373
17782
  }
17374
17783
  function normalizeGraphActivationScore(score) {
17375
17784
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -17444,7 +17853,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
17444
17853
  for (const mem of allMemsForGraph ?? []) {
17445
17854
  const id = mem.frontmatter.id;
17446
17855
  if (!id) continue;
17447
- pathById.set(id, path34.relative(storageDir, mem.path));
17856
+ pathById.set(id, path37.relative(storageDir, mem.path));
17448
17857
  }
17449
17858
  return pathById;
17450
17859
  }
@@ -17452,7 +17861,7 @@ function appendMemoryToGraphContext(options) {
17452
17861
  if (!Array.isArray(options.allMemsForGraph)) return;
17453
17862
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
17454
17863
  options.allMemsForGraph.push({
17455
- path: path34.join(options.storageDir, options.memoryRelPath),
17864
+ path: path37.join(options.storageDir, options.memoryRelPath),
17456
17865
  content: options.content,
17457
17866
  frontmatter: {
17458
17867
  id: options.memoryId,
@@ -17472,15 +17881,15 @@ function resolvePersistedMemoryRelativePath(options) {
17472
17881
  const persisted = options.pathById.get(options.memoryId);
17473
17882
  if (persisted) return persisted;
17474
17883
  if (options.category === "correction") {
17475
- return path34.join("corrections", `${options.memoryId}.md`);
17884
+ return path37.join("corrections", `${options.memoryId}.md`);
17476
17885
  }
17477
17886
  const idParts = options.memoryId.split("-");
17478
17887
  const maybeTimestamp = Number(idParts[1]);
17479
17888
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
17480
17889
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
17481
- return path34.join("facts", day, `${options.memoryId}.md`);
17890
+ return path37.join("facts", day, `${options.memoryId}.md`);
17482
17891
  }
17483
- return path34.join("facts", `${options.memoryId}.md`);
17892
+ return path37.join("facts", `${options.memoryId}.md`);
17484
17893
  }
17485
17894
  function shouldRejectLowConfidenceRecall(results, threshold) {
17486
17895
  if (results.length === 0) return false;
@@ -17588,7 +17997,7 @@ var Orchestrator = class _Orchestrator {
17588
17997
  this.compounding = config.compoundingEnabled ? new CompoundingEngine(config) : void 0;
17589
17998
  this.buffer = new SmartBuffer(config, this.storage);
17590
17999
  this.transcript = new TranscriptManager(config);
17591
- this.conversationIndexDir = path34.join(config.memoryDir, "conversation-index", "chunks");
18000
+ this.conversationIndexDir = path37.join(config.memoryDir, "conversation-index", "chunks");
17592
18001
  this.modelRegistry = new ModelRegistry(config.memoryDir);
17593
18002
  this.relevance = new RelevanceStore(config.memoryDir);
17594
18003
  this.negatives = new NegativeExampleStore(config.memoryDir);
@@ -17613,7 +18022,7 @@ var Orchestrator = class _Orchestrator {
17613
18022
  })() : this.localLlm;
17614
18023
  this.extraction = new ExtractionEngine(config, this.localLlm, config.gatewayConfig, this.modelRegistry);
17615
18024
  this.threading = new ThreadingManager(
17616
- path34.join(config.memoryDir, "threads"),
18025
+ path37.join(config.memoryDir, "threads"),
17617
18026
  config.threadingGapMinutes
17618
18027
  );
17619
18028
  this.tmtBuilder = new TmtBuilder(config.memoryDir, {
@@ -17782,7 +18191,7 @@ var Orchestrator = class _Orchestrator {
17782
18191
  await this.sessionObserver.load();
17783
18192
  this.runtimePolicyValues = await this.policyRuntime.loadRuntimeValues();
17784
18193
  if (this.config.factDeduplicationEnabled) {
17785
- const stateDir2 = path34.join(this.config.memoryDir, "state");
18194
+ const stateDir2 = path37.join(this.config.memoryDir, "state");
17786
18195
  this.contentHashIndex = new ContentHashIndex(stateDir2);
17787
18196
  await this.contentHashIndex.load();
17788
18197
  log.info(`content-hash dedup: loaded ${this.contentHashIndex.size} hashes`);
@@ -17821,7 +18230,7 @@ var Orchestrator = class _Orchestrator {
17821
18230
  if (available) {
17822
18231
  log.info(`Conversation index QMD: available ${this.conversationQmd.debugStatus()}`);
17823
18232
  const collectionState = await this.conversationQmd.ensureCollection(
17824
- path34.join(this.config.memoryDir, "conversation-index")
18233
+ path37.join(this.config.memoryDir, "conversation-index")
17825
18234
  );
17826
18235
  if (collectionState === "missing") {
17827
18236
  this.config.conversationIndexEnabled = false;
@@ -17857,7 +18266,7 @@ var Orchestrator = class _Orchestrator {
17857
18266
  const files = await readdir16(wsDir).catch(() => []);
17858
18267
  for (const f of files) {
17859
18268
  if (!f.startsWith(".compaction-reset-signal-")) continue;
17860
- const fp = path34.join(wsDir, f);
18269
+ const fp = path37.join(wsDir, f);
17861
18270
  const s = await stat7(fp).catch(() => null);
17862
18271
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
17863
18272
  await unlink5(fp).catch(() => {
@@ -17893,12 +18302,12 @@ var Orchestrator = class _Orchestrator {
17893
18302
  this.lastFileHygieneRunAtMs = now;
17894
18303
  if (hygiene.rotateEnabled) {
17895
18304
  for (const rel of hygiene.rotatePaths) {
17896
- const abs = path34.isAbsolute(rel) ? rel : path34.join(this.config.workspaceDir, rel);
18305
+ const abs = path37.isAbsolute(rel) ? rel : path37.join(this.config.workspaceDir, rel);
17897
18306
  try {
17898
18307
  const raw = await readFile23(abs, "utf-8");
17899
18308
  if (raw.length > hygiene.rotateMaxBytes) {
17900
- const archiveDir = path34.join(this.config.workspaceDir, hygiene.archiveDir);
17901
- const base = path34.basename(abs);
18309
+ const archiveDir = path37.join(this.config.workspaceDir, hygiene.archiveDir);
18310
+ const base = path37.basename(abs);
17902
18311
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
17903
18312
  const { newContent } = await rotateMarkdownFileToArchive({
17904
18313
  filePath: abs,
@@ -17906,7 +18315,7 @@ var Orchestrator = class _Orchestrator {
17906
18315
  archivePrefix: prefix,
17907
18316
  keepTailChars: hygiene.rotateKeepTailChars
17908
18317
  });
17909
- await writeFile24(abs, newContent, "utf-8");
18318
+ await writeFile26(abs, newContent, "utf-8");
17910
18319
  }
17911
18320
  } catch {
17912
18321
  }
@@ -17923,8 +18332,8 @@ var Orchestrator = class _Orchestrator {
17923
18332
  log.warn(w.message);
17924
18333
  }
17925
18334
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
17926
- const fp = path34.join(this.config.memoryDir, hygiene.warningsLogPath);
17927
- await mkdir24(path34.dirname(fp), { recursive: true });
18335
+ const fp = path37.join(this.config.memoryDir, hygiene.warningsLogPath);
18336
+ await mkdir26(path37.dirname(fp), { recursive: true });
17928
18337
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
17929
18338
  const block = `
17930
18339
 
@@ -17937,7 +18346,7 @@ var Orchestrator = class _Orchestrator {
17937
18346
  } catch {
17938
18347
  existing = "# Engram File Hygiene Warnings\n";
17939
18348
  }
17940
- await writeFile24(fp, existing + block, "utf-8");
18349
+ await writeFile26(fp, existing + block, "utf-8");
17941
18350
  }
17942
18351
  }
17943
18352
  }
@@ -18013,7 +18422,7 @@ var Orchestrator = class _Orchestrator {
18013
18422
  }
18014
18423
  async getLastGraphRecallSnapshot(namespace) {
18015
18424
  const storage = await this.getStorage(namespace);
18016
- const snapshotPath = path34.join(storage.dir, "state", "last_graph_recall.json");
18425
+ const snapshotPath = path37.join(storage.dir, "state", "last_graph_recall.json");
18017
18426
  try {
18018
18427
  const raw = await readFile23(snapshotPath, "utf-8");
18019
18428
  const parsed = JSON.parse(raw);
@@ -18084,7 +18493,7 @@ ${r.snippet.trim()}
18084
18493
  const entries = await readdir16(dir, { withFileTypes: true });
18085
18494
  let total = 0;
18086
18495
  for (const entry of entries) {
18087
- const fullPath = path34.join(dir, entry.name);
18496
+ const fullPath = path37.join(dir, entry.name);
18088
18497
  if (entry.isDirectory()) {
18089
18498
  total += await this.countConversationChunkDocs(fullPath);
18090
18499
  continue;
@@ -18409,7 +18818,7 @@ ${r.snippet.trim()}
18409
18818
  const seedRelativePaths = seedCandidates.map((result) => graphPathRelativeToStorage(storage.dir, result.path)).filter((value) => typeof value === "string" && value.length > 0);
18410
18819
  if (seedRelativePaths.length === 0) continue;
18411
18820
  const seedRecallScore = seedCandidates.reduce((max, item) => Math.max(max, item.score), 0);
18412
- seedPaths.push(...seedRelativePaths.map((rel) => path34.join(storage.dir, rel)));
18821
+ seedPaths.push(...seedRelativePaths.map((rel) => path37.join(storage.dir, rel)));
18413
18822
  const seedSet = new Set(seedRelativePaths);
18414
18823
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
18415
18824
  seedRelativePaths,
@@ -18418,7 +18827,7 @@ ${r.snippet.trim()}
18418
18827
  if (expanded.length === 0) continue;
18419
18828
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
18420
18829
  if (seedSet.has(candidate.path)) continue;
18421
- const memoryPath = path34.resolve(storage.dir, candidate.path);
18830
+ const memoryPath = path37.resolve(storage.dir, candidate.path);
18422
18831
  const memory = await storage.readMemoryByPath(memoryPath);
18423
18832
  if (!memory) continue;
18424
18833
  if (isArtifactMemoryPath(memory.path)) continue;
@@ -18441,7 +18850,7 @@ ${r.snippet.trim()}
18441
18850
  path: memory.path,
18442
18851
  score,
18443
18852
  namespace,
18444
- seed: path34.resolve(storage.dir, candidate.seed),
18853
+ seed: path37.resolve(storage.dir, candidate.seed),
18445
18854
  hopDepth: candidate.hopDepth,
18446
18855
  decayedWeight: candidate.decayedWeight,
18447
18856
  graphType: candidate.graphType
@@ -18456,8 +18865,8 @@ ${r.snippet.trim()}
18456
18865
  }
18457
18866
  async recordLastGraphRecallSnapshot(options) {
18458
18867
  try {
18459
- const snapshotPath = path34.join(options.storage.dir, "state", "last_graph_recall.json");
18460
- await mkdir24(path34.dirname(snapshotPath), { recursive: true });
18868
+ const snapshotPath = path37.join(options.storage.dir, "state", "last_graph_recall.json");
18869
+ await mkdir26(path37.dirname(snapshotPath), { recursive: true });
18461
18870
  const now = (/* @__PURE__ */ new Date()).toISOString();
18462
18871
  const totalSeedCount = options.seedPaths.length;
18463
18872
  const totalExpandedCount = options.expandedPaths.length;
@@ -18474,7 +18883,7 @@ ${r.snippet.trim()}
18474
18883
  seeds,
18475
18884
  expanded
18476
18885
  };
18477
- await writeFile24(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
18886
+ await writeFile26(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
18478
18887
  } catch (err) {
18479
18888
  log.debug(`last graph recall write failed: ${err}`);
18480
18889
  }
@@ -18783,7 +19192,49 @@ ${r.snippet.trim()}
18783
19192
  timings.trustZones = `${Date.now() - t0}ms`;
18784
19193
  return results.length > 0 ? this.formatTrustZoneResults(results) : null;
18785
19194
  })();
18786
- const qmdPromise = (async () => {
19195
+ const harmonicRetrievalPromise = (async () => {
19196
+ const t0 = Date.now();
19197
+ if (!this.config.harmonicRetrievalEnabled || !this.isRecallSectionEnabled("harmonic-retrieval", this.config.harmonicRetrievalEnabled === true)) {
19198
+ timings.harmonicRetrieval = "skip";
19199
+ return null;
19200
+ }
19201
+ const maxResults = this.getRecallSectionNumber("harmonic-retrieval", "maxResults") ?? 3;
19202
+ if (maxResults <= 0) {
19203
+ timings.harmonicRetrieval = "skip(limit=0)";
19204
+ return null;
19205
+ }
19206
+ const results = await searchHarmonicRetrieval({
19207
+ memoryDir: this.config.memoryDir,
19208
+ abstractionNodeStoreDir: this.config.abstractionNodeStoreDir,
19209
+ query: retrievalQuery,
19210
+ maxResults,
19211
+ sessionKey,
19212
+ anchorsEnabled: this.config.abstractionAnchorsEnabled
19213
+ });
19214
+ timings.harmonicRetrieval = `${Date.now() - t0}ms`;
19215
+ return results.length > 0 ? this.formatHarmonicRetrievalResults(results) : null;
19216
+ })();
19217
+ const verifiedRecallPromise = (async () => {
19218
+ const t0 = Date.now();
19219
+ if (!this.config.verifiedRecallEnabled || !this.isRecallSectionEnabled("verified-episodes", this.config.verifiedRecallEnabled === true)) {
19220
+ timings.verifiedRecall = "skip";
19221
+ return null;
19222
+ }
19223
+ const maxResults = this.getRecallSectionNumber("verified-episodes", "maxResults") ?? 3;
19224
+ if (maxResults <= 0) {
19225
+ timings.verifiedRecall = "skip(limit=0)";
19226
+ return null;
19227
+ }
19228
+ const results = await searchVerifiedEpisodes({
19229
+ memoryDir: this.config.memoryDir,
19230
+ query: retrievalQuery,
19231
+ maxResults,
19232
+ boxRecallDays: this.config.boxRecallDays
19233
+ });
19234
+ timings.verifiedRecall = `${Date.now() - t0}ms`;
19235
+ return results.length > 0 ? this.formatVerifiedEpisodeResults(results) : null;
19236
+ })();
19237
+ const qmdPromise = (async () => {
18787
19238
  if (recallResultLimit <= 0) {
18788
19239
  timings.qmd = "skip(limit=0)";
18789
19240
  return null;
@@ -18856,8 +19307,8 @@ ${formatted}`;
18856
19307
  if (!this.config.compactionResetEnabled) return null;
18857
19308
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
18858
19309
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
18859
- const signalPath = path34.join(workspaceDir, `.compaction-reset-signal-${safeSessionKey}`);
18860
- const bootPath = path34.join(workspaceDir, "BOOT.md");
19310
+ const signalPath = path37.join(workspaceDir, `.compaction-reset-signal-${safeSessionKey}`);
19311
+ const bootPath = path37.join(workspaceDir, "BOOT.md");
18861
19312
  try {
18862
19313
  const signalStat = await stat7(signalPath).catch(() => null);
18863
19314
  if (!signalStat) return null;
@@ -18989,6 +19440,8 @@ ${formatted}`;
18989
19440
  objectiveStateSection,
18990
19441
  causalTrajectorySection,
18991
19442
  trustZoneSection,
19443
+ harmonicRetrievalSection,
19444
+ verifiedRecallSection,
18992
19445
  qmdResult,
18993
19446
  transcriptSection,
18994
19447
  compactionSection,
@@ -19004,6 +19457,8 @@ ${formatted}`;
19004
19457
  objectiveStatePromise,
19005
19458
  causalTrajectoryPromise,
19006
19459
  trustZonePromise,
19460
+ harmonicRetrievalPromise,
19461
+ verifiedRecallPromise,
19007
19462
  qmdPromise,
19008
19463
  transcriptPromise,
19009
19464
  compactionPromise,
@@ -19067,6 +19522,12 @@ ${tmtNode.summary}`);
19067
19522
  if (trustZoneSection) {
19068
19523
  this.appendRecallSection(sectionBuckets, "trust-zones", trustZoneSection);
19069
19524
  }
19525
+ if (harmonicRetrievalSection) {
19526
+ this.appendRecallSection(sectionBuckets, "harmonic-retrieval", harmonicRetrievalSection);
19527
+ }
19528
+ if (verifiedRecallSection) {
19529
+ this.appendRecallSection(sectionBuckets, "verified-episodes", verifiedRecallSection);
19530
+ }
19070
19531
  if (qmdResult) {
19071
19532
  const t0 = Date.now();
19072
19533
  const { memoryResultsLists, globalResults } = qmdResult;
@@ -19860,7 +20321,7 @@ _Context: ${topQuestion.context}_`
19860
20321
  };
19861
20322
  this.tierMigrationInFlight = true;
19862
20323
  try {
19863
- const coldStorage = new StorageManager(path34.join(storage.dir, "cold"));
20324
+ const coldStorage = new StorageManager(path37.join(storage.dir, "cold"));
19864
20325
  const [hotMemories, coldMemories] = await Promise.all([
19865
20326
  storage.readAllMemories(),
19866
20327
  coldStorage.readAllMemories()
@@ -20454,7 +20915,7 @@ _Context: ${topQuestion.context}_`
20454
20915
  const allMems = allMemsForGraph ?? [];
20455
20916
  for (const m of allMems) {
20456
20917
  if (m.frontmatter.entityRef === entityRef) {
20457
- const rel = path34.relative(storage.dir, m.path);
20918
+ const rel = path37.relative(storage.dir, m.path);
20458
20919
  if (rel !== memoryRelPath) entitySiblings.push(rel);
20459
20920
  }
20460
20921
  }
@@ -21018,9 +21479,9 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
21018
21479
  protectedCategories: this.config.lifecycleProtectedCategories
21019
21480
  }
21020
21481
  };
21021
- const metricsPath = path34.join(this.storage.dir, "state", "lifecycle-metrics.json");
21022
- await mkdir24(path34.dirname(metricsPath), { recursive: true });
21023
- await writeFile24(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
21482
+ const metricsPath = path37.join(this.storage.dir, "state", "lifecycle-metrics.json");
21483
+ await mkdir26(path37.dirname(metricsPath), { recursive: true });
21484
+ await writeFile26(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
21024
21485
  }
21025
21486
  /**
21026
21487
  * Archive old, low-importance, rarely-accessed facts (v6.0).
@@ -21242,6 +21703,54 @@ ${details.join("\n")}`;
21242
21703
  });
21243
21704
  return `## Trust Zones
21244
21705
 
21706
+ ${lines.join("\n\n")}`;
21707
+ }
21708
+ formatHarmonicRetrievalResults(results) {
21709
+ const lines = results.map(({ node, matchedAnchors, matchedFields, nodeScore, anchorScore }, index) => {
21710
+ const header = [
21711
+ `[${index + 1}] ${node.recordedAt.replace("T", " ").slice(0, 16)}`,
21712
+ `${node.kind}/${node.abstractionLevel}`,
21713
+ node.sessionKey
21714
+ ].join(" | ");
21715
+ const details = [
21716
+ node.title,
21717
+ node.summary,
21718
+ `scores: node=${nodeScore.toFixed(1)} anchor=${anchorScore.toFixed(1)}`
21719
+ ];
21720
+ if (matchedAnchors.length > 0) {
21721
+ details.push(`anchors: ${matchedAnchors.map((anchor) => `${anchor.anchorType}:${anchor.anchorValue}`).join("; ")}`);
21722
+ }
21723
+ if (matchedFields.length > 0) {
21724
+ details.push(`matched: ${matchedFields.join(", ")}`);
21725
+ }
21726
+ return `${header}
21727
+ ${details.join("\n")}`;
21728
+ });
21729
+ return `## Harmonic Retrieval
21730
+
21731
+ ${lines.join("\n\n")}`;
21732
+ }
21733
+ formatVerifiedEpisodeResults(results) {
21734
+ const lines = results.map(({ box, verifiedEpisodeCount, matchedFields }, index) => {
21735
+ const header = [
21736
+ `[${index + 1}] ${box.sealedAt.replace("T", " ").slice(0, 16)}`,
21737
+ box.traceId ? `trace:${box.traceId.slice(0, 12)}` : "trace:none"
21738
+ ].join(" | ");
21739
+ const details = [
21740
+ box.goal ?? `topics: ${box.topics.join(", ")}`,
21741
+ `verified episodes: ${verifiedEpisodeCount}`
21742
+ ];
21743
+ if (box.toolsUsed && box.toolsUsed.length > 0) {
21744
+ details.push(`tools: ${box.toolsUsed.join(", ")}`);
21745
+ }
21746
+ if (matchedFields.length > 0) {
21747
+ details.push(`matched: ${matchedFields.join(", ")}`);
21748
+ }
21749
+ return `${header}
21750
+ ${details.join("\n")}`;
21751
+ });
21752
+ return `## Verified Episodes
21753
+
21245
21754
  ${lines.join("\n\n")}`;
21246
21755
  }
21247
21756
  summarizeIdentityText(raw, maxLines, maxChars) {
@@ -21375,7 +21884,7 @@ ${lines.join("\n\n")}`;
21375
21884
  if (hits.length === 0) return [];
21376
21885
  const results = [];
21377
21886
  for (const hit of hits) {
21378
- const fullPath = path34.isAbsolute(hit.path) ? hit.path : path34.join(this.config.memoryDir, hit.path);
21887
+ const fullPath = path37.isAbsolute(hit.path) ? hit.path : path37.join(this.config.memoryDir, hit.path);
21379
21888
  const memory = await this.storage.readMemoryByPath(fullPath);
21380
21889
  if (!memory) continue;
21381
21890
  results.push({
@@ -21833,8 +22342,8 @@ ${lines.join("\n\n")}`;
21833
22342
  }
21834
22343
  namespaceFromStorageDir(storageDir) {
21835
22344
  if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
21836
- const resolvedStorageDir = path34.resolve(storageDir);
21837
- const resolvedMemoryDir = path34.resolve(this.config.memoryDir);
22345
+ const resolvedStorageDir = path37.resolve(storageDir);
22346
+ const resolvedMemoryDir = path37.resolve(this.config.memoryDir);
21838
22347
  if (resolvedStorageDir === resolvedMemoryDir) return this.config.defaultNamespace;
21839
22348
  const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
21840
22349
  return m && m[1] ? m[1] : this.config.defaultNamespace;
@@ -21862,14 +22371,14 @@ ${lines.join("\n\n")}`;
21862
22371
  };
21863
22372
 
21864
22373
  // src/tools.ts
21865
- import path36 from "path";
22374
+ import path39 from "path";
21866
22375
  import { createHash as createHash7 } from "crypto";
21867
22376
  import { Type } from "@sinclair/typebox";
21868
22377
 
21869
22378
  // src/work/storage.ts
21870
- import path35 from "path";
22379
+ import path38 from "path";
21871
22380
  import { randomUUID } from "crypto";
21872
- import { mkdir as mkdir25, readdir as readdir17, readFile as readFile24, rm as rm4, writeFile as writeFile25 } from "fs/promises";
22381
+ import { mkdir as mkdir27, readdir as readdir17, readFile as readFile24, rm as rm4, writeFile as writeFile27 } from "fs/promises";
21873
22382
  var TASK_TRANSITIONS = {
21874
22383
  todo: /* @__PURE__ */ new Set(["in_progress", "blocked", "cancelled"]),
21875
22384
  in_progress: /* @__PURE__ */ new Set(["todo", "blocked", "done", "cancelled"]),
@@ -21944,22 +22453,22 @@ function ensureProjectStatus(value) {
21944
22453
  var WorkStorage = class {
21945
22454
  constructor(memoryDir) {
21946
22455
  this.memoryDir = memoryDir;
21947
- this.tasksDir = path35.join(memoryDir, "work", "tasks");
21948
- this.projectsDir = path35.join(memoryDir, "work", "projects");
22456
+ this.tasksDir = path38.join(memoryDir, "work", "tasks");
22457
+ this.projectsDir = path38.join(memoryDir, "work", "projects");
21949
22458
  }
21950
22459
  tasksDir;
21951
22460
  projectsDir;
21952
22461
  async ensureDirectories() {
21953
- await mkdir25(this.tasksDir, { recursive: true });
21954
- await mkdir25(this.projectsDir, { recursive: true });
22462
+ await mkdir27(this.tasksDir, { recursive: true });
22463
+ await mkdir27(this.projectsDir, { recursive: true });
21955
22464
  }
21956
22465
  taskPath(id) {
21957
22466
  assertValidWorkId(id, "task");
21958
- return path35.join(this.tasksDir, `${id}.md`);
22467
+ return path38.join(this.tasksDir, `${id}.md`);
21959
22468
  }
21960
22469
  projectPath(id) {
21961
22470
  assertValidWorkId(id, "project");
21962
- return path35.join(this.projectsDir, `${id}.md`);
22471
+ return path38.join(this.projectsDir, `${id}.md`);
21963
22472
  }
21964
22473
  serializeTask(task) {
21965
22474
  return `${serializeFrontmatter2(task)}
@@ -22031,7 +22540,7 @@ ${project.description}
22031
22540
  throw new Error(`project not found: ${task.projectId}`);
22032
22541
  }
22033
22542
  }
22034
- await writeFile25(this.taskPath(task.id), this.serializeTask(task), "utf-8");
22543
+ await writeFile27(this.taskPath(task.id), this.serializeTask(task), "utf-8");
22035
22544
  if (task.projectId) {
22036
22545
  await this.addTaskIdToProject(task.projectId, task.id, now);
22037
22546
  }
@@ -22051,7 +22560,7 @@ ${project.description}
22051
22560
  const out = [];
22052
22561
  for (const entry of entries) {
22053
22562
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
22054
- const raw = await readFile24(path35.join(this.tasksDir, entry.name), "utf-8");
22563
+ const raw = await readFile24(path38.join(this.tasksDir, entry.name), "utf-8");
22055
22564
  const task = this.parseTask(raw);
22056
22565
  if (!task) continue;
22057
22566
  if (filter?.status && task.status !== filter.status) continue;
@@ -22093,7 +22602,7 @@ ${project.description}
22093
22602
  tags: patch.tags ?? existing.tags,
22094
22603
  updatedAt: now.toISOString()
22095
22604
  };
22096
- await writeFile25(this.taskPath(id), this.serializeTask(next), "utf-8");
22605
+ await writeFile27(this.taskPath(id), this.serializeTask(next), "utf-8");
22097
22606
  return next;
22098
22607
  }
22099
22608
  async transitionTask(id, nextStatus, now = /* @__PURE__ */ new Date()) {
@@ -22133,7 +22642,7 @@ ${project.description}
22133
22642
  createdAt: timestamp,
22134
22643
  updatedAt: timestamp
22135
22644
  };
22136
- await writeFile25(this.projectPath(project.id), this.serializeProject(project), "utf-8");
22645
+ await writeFile27(this.projectPath(project.id), this.serializeProject(project), "utf-8");
22137
22646
  return project;
22138
22647
  }
22139
22648
  async getProject(id) {
@@ -22150,7 +22659,7 @@ ${project.description}
22150
22659
  const out = [];
22151
22660
  for (const entry of entries) {
22152
22661
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
22153
- const raw = await readFile24(path35.join(this.projectsDir, entry.name), "utf-8");
22662
+ const raw = await readFile24(path38.join(this.projectsDir, entry.name), "utf-8");
22154
22663
  const project = this.parseProject(raw);
22155
22664
  if (project) out.push(project);
22156
22665
  }
@@ -22167,7 +22676,7 @@ ${project.description}
22167
22676
  taskIds: patch.taskIds ? [...patch.taskIds].sort() : existing.taskIds,
22168
22677
  updatedAt: now.toISOString()
22169
22678
  };
22170
- await writeFile25(this.projectPath(id), this.serializeProject(next), "utf-8");
22679
+ await writeFile27(this.projectPath(id), this.serializeProject(next), "utf-8");
22171
22680
  return next;
22172
22681
  }
22173
22682
  async deleteProject(id) {
@@ -23706,7 +24215,7 @@ Best for:
23706
24215
  - Reviewing identity development over time`,
23707
24216
  parameters: Type.Object({}),
23708
24217
  async execute() {
23709
- const workspaceDir = path36.join(process.env.HOME ?? "~", ".openclaw", "workspace");
24218
+ const workspaceDir = path39.join(process.env.HOME ?? "~", ".openclaw", "workspace");
23710
24219
  const identity = await orchestrator.storage.readIdentity(workspaceDir);
23711
24220
  if (!identity) {
23712
24221
  return toolResult("No identity file found. Identity reflections build automatically through conversations when identityEnabled is true.");
@@ -24223,13 +24732,13 @@ promotionCandidates: ${res.promotionCandidateCount}`
24223
24732
  }
24224
24733
 
24225
24734
  // src/cli.ts
24226
- import path56 from "path";
24735
+ import path57 from "path";
24227
24736
  import { access as access3, readFile as readFile37, readdir as readdir24, unlink as unlink7 } from "fs/promises";
24228
24737
  import { createHash as createHash10 } from "crypto";
24229
24738
 
24230
24739
  // src/transfer/export-json.ts
24231
- import path38 from "path";
24232
- import { mkdir as mkdir27, readFile as readFile26 } from "fs/promises";
24740
+ import path41 from "path";
24741
+ import { mkdir as mkdir29, readFile as readFile26 } from "fs/promises";
24233
24742
 
24234
24743
  // src/transfer/constants.ts
24235
24744
  var EXPORT_FORMAT = "openclaw-engram-export";
@@ -24237,8 +24746,8 @@ var EXPORT_SCHEMA_VERSION = 1;
24237
24746
 
24238
24747
  // src/transfer/fs-utils.ts
24239
24748
  import { createHash as createHash8 } from "crypto";
24240
- import { mkdir as mkdir26, readdir as readdir18, readFile as readFile25, stat as stat8, writeFile as writeFile26 } from "fs/promises";
24241
- import path37 from "path";
24749
+ import { mkdir as mkdir28, readdir as readdir18, readFile as readFile25, stat as stat8, writeFile as writeFile28 } from "fs/promises";
24750
+ import path40 from "path";
24242
24751
  async function sha256File(filePath) {
24243
24752
  const buf = await readFile25(filePath);
24244
24753
  const sha256 = createHash8("sha256").update(buf).digest("hex");
@@ -24250,8 +24759,8 @@ function sha256String(content) {
24250
24759
  return { sha256, bytes: buf.byteLength };
24251
24760
  }
24252
24761
  async function writeJsonFile(filePath, value) {
24253
- await mkdir26(path37.dirname(filePath), { recursive: true });
24254
- await writeFile26(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
24762
+ await mkdir28(path40.dirname(filePath), { recursive: true });
24763
+ await writeFile28(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
24255
24764
  }
24256
24765
  async function readJsonFile2(filePath) {
24257
24766
  const raw = await readFile25(filePath, "utf-8");
@@ -24262,7 +24771,7 @@ async function listFilesRecursive(rootDir) {
24262
24771
  async function walk(dir) {
24263
24772
  const entries = await readdir18(dir, { withFileTypes: true });
24264
24773
  for (const ent of entries) {
24265
- const fp = path37.join(dir, ent.name);
24774
+ const fp = path40.join(dir, ent.name);
24266
24775
  if (ent.isDirectory()) {
24267
24776
  await walk(fp);
24268
24777
  } else if (ent.isFile()) {
@@ -24282,11 +24791,11 @@ async function fileExists(filePath) {
24282
24791
  }
24283
24792
  }
24284
24793
  function toPosixRelPath(absPath, rootDir) {
24285
- const rel = path37.relative(rootDir, absPath);
24286
- return rel.split(path37.sep).join("/");
24794
+ const rel = path40.relative(rootDir, absPath);
24795
+ return rel.split(path40.sep).join("/");
24287
24796
  }
24288
24797
  function fromPosixRelPath(relPath) {
24289
- return relPath.split("/").join(path37.sep);
24798
+ return relPath.split("/").join(path40.sep);
24290
24799
  }
24291
24800
 
24292
24801
  // src/transfer/export-json.ts
@@ -24302,9 +24811,9 @@ function shouldExclude(relPosix, includeTranscripts) {
24302
24811
  }
24303
24812
  async function exportJsonBundle(opts) {
24304
24813
  const includeTranscripts = opts.includeTranscripts === true;
24305
- const outDirAbs = path38.resolve(opts.outDir);
24306
- await mkdir27(outDirAbs, { recursive: true });
24307
- const memoryDirAbs = path38.resolve(opts.memoryDir);
24814
+ const outDirAbs = path41.resolve(opts.outDir);
24815
+ await mkdir29(outDirAbs, { recursive: true });
24816
+ const memoryDirAbs = path41.resolve(opts.memoryDir);
24308
24817
  const filesAbs = await listFilesRecursive(memoryDirAbs);
24309
24818
  const records = [];
24310
24819
  const manifestFiles = [];
@@ -24317,7 +24826,7 @@ async function exportJsonBundle(opts) {
24317
24826
  manifestFiles.push({ path: relPosix, sha256, bytes });
24318
24827
  }
24319
24828
  if (opts.includeWorkspaceIdentity !== false && opts.workspaceDir) {
24320
- const identityPath = path38.join(opts.workspaceDir, "IDENTITY.md");
24829
+ const identityPath = path41.join(opts.workspaceDir, "IDENTITY.md");
24321
24830
  try {
24322
24831
  const content = await readFile26(identityPath, "utf-8");
24323
24832
  const relPath = "workspace/IDENTITY.md";
@@ -24336,13 +24845,13 @@ async function exportJsonBundle(opts) {
24336
24845
  files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
24337
24846
  };
24338
24847
  const bundle = { manifest, records };
24339
- await writeJsonFile(path38.join(outDirAbs, "manifest.json"), manifest);
24340
- await writeJsonFile(path38.join(outDirAbs, "bundle.json"), bundle);
24848
+ await writeJsonFile(path41.join(outDirAbs, "manifest.json"), manifest);
24849
+ await writeJsonFile(path41.join(outDirAbs, "bundle.json"), bundle);
24341
24850
  }
24342
24851
 
24343
24852
  // src/transfer/export-md.ts
24344
- import path39 from "path";
24345
- import { mkdir as mkdir28, readFile as readFile27, writeFile as writeFile27 } from "fs/promises";
24853
+ import path42 from "path";
24854
+ import { mkdir as mkdir30, readFile as readFile27, writeFile as writeFile29 } from "fs/promises";
24346
24855
  function shouldExclude2(relPosix, includeTranscripts) {
24347
24856
  const parts = relPosix.split("/");
24348
24857
  if (!includeTranscripts && parts[0] === "transcripts") return true;
@@ -24350,18 +24859,18 @@ function shouldExclude2(relPosix, includeTranscripts) {
24350
24859
  }
24351
24860
  async function exportMarkdownBundle(opts) {
24352
24861
  const includeTranscripts = opts.includeTranscripts === true;
24353
- const outDirAbs = path39.resolve(opts.outDir);
24354
- await mkdir28(outDirAbs, { recursive: true });
24355
- const memDirAbs = path39.resolve(opts.memoryDir);
24862
+ const outDirAbs = path42.resolve(opts.outDir);
24863
+ await mkdir30(outDirAbs, { recursive: true });
24864
+ const memDirAbs = path42.resolve(opts.memoryDir);
24356
24865
  const filesAbs = await listFilesRecursive(memDirAbs);
24357
24866
  const manifestFiles = [];
24358
24867
  for (const abs of filesAbs) {
24359
24868
  const relPosix = toPosixRelPath(abs, memDirAbs);
24360
24869
  if (shouldExclude2(relPosix, includeTranscripts)) continue;
24361
- const dstAbs = path39.join(outDirAbs, ...relPosix.split("/"));
24362
- await mkdir28(path39.dirname(dstAbs), { recursive: true });
24870
+ const dstAbs = path42.join(outDirAbs, ...relPosix.split("/"));
24871
+ await mkdir30(path42.dirname(dstAbs), { recursive: true });
24363
24872
  const content = await readFile27(abs);
24364
- await writeFile27(dstAbs, content);
24873
+ await writeFile29(dstAbs, content);
24365
24874
  const { sha256, bytes } = await sha256File(abs);
24366
24875
  manifestFiles.push({ path: relPosix, sha256, bytes });
24367
24876
  }
@@ -24373,12 +24882,12 @@ async function exportMarkdownBundle(opts) {
24373
24882
  includesTranscripts: includeTranscripts,
24374
24883
  files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
24375
24884
  };
24376
- await writeJsonFile(path39.join(outDirAbs, "manifest.json"), manifest);
24885
+ await writeJsonFile(path42.join(outDirAbs, "manifest.json"), manifest);
24377
24886
  }
24378
24887
  async function looksLikeEngramMdExport(fromDir) {
24379
- const dirAbs = path39.resolve(fromDir);
24888
+ const dirAbs = path42.resolve(fromDir);
24380
24889
  try {
24381
- const raw = await readFile27(path39.join(dirAbs, "manifest.json"), "utf-8");
24890
+ const raw = await readFile27(path42.join(dirAbs, "manifest.json"), "utf-8");
24382
24891
  const parsed = JSON.parse(raw);
24383
24892
  return parsed.format === EXPORT_FORMAT && parsed.schemaVersion === EXPORT_SCHEMA_VERSION;
24384
24893
  } catch {
@@ -24387,16 +24896,16 @@ async function looksLikeEngramMdExport(fromDir) {
24387
24896
  }
24388
24897
 
24389
24898
  // src/transfer/backup.ts
24390
- import path40 from "path";
24391
- import { mkdir as mkdir29, readdir as readdir19, rm as rm5 } from "fs/promises";
24899
+ import path43 from "path";
24900
+ import { mkdir as mkdir31, readdir as readdir19, rm as rm5 } from "fs/promises";
24392
24901
  function timestampDirName(now) {
24393
24902
  return now.toISOString().replace(/[:.]/g, "-");
24394
24903
  }
24395
24904
  async function backupMemoryDir(opts) {
24396
- const outDirAbs = path40.resolve(opts.outDir);
24397
- await mkdir29(outDirAbs, { recursive: true });
24905
+ const outDirAbs = path43.resolve(opts.outDir);
24906
+ await mkdir31(outDirAbs, { recursive: true });
24398
24907
  const ts = timestampDirName(/* @__PURE__ */ new Date());
24399
- const backupDir = path40.join(outDirAbs, ts);
24908
+ const backupDir = path43.join(outDirAbs, ts);
24400
24909
  await exportMarkdownBundle({
24401
24910
  memoryDir: opts.memoryDir,
24402
24911
  outDir: backupDir,
@@ -24421,13 +24930,13 @@ async function enforceRetention(outDirAbs, retentionDays) {
24421
24930
  const tsMs = iso ? Date.parse(iso) : NaN;
24422
24931
  if (!Number.isFinite(tsMs)) continue;
24423
24932
  if (tsMs < cutoffMs) {
24424
- await rm5(path40.join(outDirAbs, name), { recursive: true, force: true });
24933
+ await rm5(path43.join(outDirAbs, name), { recursive: true, force: true });
24425
24934
  }
24426
24935
  }
24427
24936
  }
24428
24937
 
24429
24938
  // src/transfer/export-sqlite.ts
24430
- import path41 from "path";
24939
+ import path44 from "path";
24431
24940
  import Database from "better-sqlite3";
24432
24941
  import { readFile as readFile28 } from "fs/promises";
24433
24942
 
@@ -24455,8 +24964,8 @@ function shouldExclude3(relPosix, includeTranscripts) {
24455
24964
  }
24456
24965
  async function exportSqlite(opts) {
24457
24966
  const includeTranscripts = opts.includeTranscripts === true;
24458
- const memDirAbs = path41.resolve(opts.memoryDir);
24459
- const outAbs = path41.resolve(opts.outFile);
24967
+ const memDirAbs = path44.resolve(opts.memoryDir);
24968
+ const outAbs = path44.resolve(opts.outFile);
24460
24969
  const filesAbs = await listFilesRecursive(memDirAbs);
24461
24970
  const db = new Database(outAbs);
24462
24971
  try {
@@ -24488,8 +24997,8 @@ async function exportSqlite(opts) {
24488
24997
  }
24489
24998
 
24490
24999
  // src/transfer/import-json.ts
24491
- import path42 from "path";
24492
- import { mkdir as mkdir30, writeFile as writeFile28 } from "fs/promises";
25000
+ import path45 from "path";
25001
+ import { mkdir as mkdir32, writeFile as writeFile30 } from "fs/promises";
24493
25002
 
24494
25003
  // src/transfer/types.ts
24495
25004
  import { z as z4 } from "zod";
@@ -24522,21 +25031,21 @@ function normalizeForDedupe(s) {
24522
25031
  }
24523
25032
  async function importJsonBundle(opts) {
24524
25033
  const conflict = opts.conflict ?? "skip";
24525
- const fromDirAbs = path42.resolve(opts.fromDir);
24526
- const bundlePath = path42.join(fromDirAbs, "bundle.json");
25034
+ const fromDirAbs = path45.resolve(opts.fromDir);
25035
+ const bundlePath = path45.join(fromDirAbs, "bundle.json");
24527
25036
  const bundle = ExportBundleV1Schema.parse(await readJsonFile2(bundlePath));
24528
- const memDirAbs = path42.resolve(opts.targetMemoryDir);
25037
+ const memDirAbs = path45.resolve(opts.targetMemoryDir);
24529
25038
  const written = [];
24530
25039
  let skipped = 0;
24531
25040
  for (const rec of bundle.records) {
24532
25041
  const isWorkspace = rec.path.startsWith("workspace/");
24533
- const targetBase = isWorkspace ? opts.workspaceDir ? path42.resolve(opts.workspaceDir) : null : memDirAbs;
25042
+ const targetBase = isWorkspace ? opts.workspaceDir ? path45.resolve(opts.workspaceDir) : null : memDirAbs;
24534
25043
  if (isWorkspace && !targetBase) {
24535
25044
  skipped += 1;
24536
25045
  continue;
24537
25046
  }
24538
25047
  const relFs = fromPosixRelPath(isWorkspace ? rec.path.replace(/^workspace\//, "") : rec.path);
24539
- const absTarget = path42.join(targetBase, relFs);
25048
+ const absTarget = path45.join(targetBase, relFs);
24540
25049
  const exists3 = await fileExists(absTarget);
24541
25050
  if (exists3) {
24542
25051
  if (conflict === "skip") {
@@ -24560,30 +25069,30 @@ async function importJsonBundle(opts) {
24560
25069
  return { written: 0, skipped };
24561
25070
  }
24562
25071
  for (const w of written) {
24563
- await mkdir30(path42.dirname(w.abs), { recursive: true });
24564
- await writeFile28(w.abs, w.content, "utf-8");
25072
+ await mkdir32(path45.dirname(w.abs), { recursive: true });
25073
+ await writeFile30(w.abs, w.content, "utf-8");
24565
25074
  }
24566
25075
  return { written: written.length, skipped };
24567
25076
  }
24568
25077
  function looksLikeEngramJsonExport(fromDir) {
24569
- const dir = path42.resolve(fromDir);
25078
+ const dir = path45.resolve(fromDir);
24570
25079
  return Promise.all([
24571
- fileExists(path42.join(dir, "manifest.json")),
24572
- fileExists(path42.join(dir, "bundle.json"))
25080
+ fileExists(path45.join(dir, "manifest.json")),
25081
+ fileExists(path45.join(dir, "bundle.json"))
24573
25082
  ]).then(([m, b]) => m && b);
24574
25083
  }
24575
25084
 
24576
25085
  // src/transfer/import-sqlite.ts
24577
- import path43 from "path";
25086
+ import path46 from "path";
24578
25087
  import Database2 from "better-sqlite3";
24579
- import { mkdir as mkdir31, writeFile as writeFile29 } from "fs/promises";
25088
+ import { mkdir as mkdir33, writeFile as writeFile31 } from "fs/promises";
24580
25089
  function normalizeForDedupe2(s) {
24581
25090
  return s.replace(/\s+/g, " ").trim();
24582
25091
  }
24583
25092
  async function importSqlite(opts) {
24584
25093
  const conflict = opts.conflict ?? "skip";
24585
- const memDirAbs = path43.resolve(opts.targetMemoryDir);
24586
- const fromAbs = path43.resolve(opts.fromFile);
25094
+ const memDirAbs = path46.resolve(opts.targetMemoryDir);
25095
+ const fromAbs = path46.resolve(opts.fromFile);
24587
25096
  const db = new Database2(fromAbs, { readonly: true });
24588
25097
  const written = [];
24589
25098
  let skipped = 0;
@@ -24596,7 +25105,7 @@ async function importSqlite(opts) {
24596
25105
  const rows = db.prepare("SELECT path_rel, content FROM files").all();
24597
25106
  for (const r of rows) {
24598
25107
  const relFs = fromPosixRelPath(r.path_rel);
24599
- const absTarget = path43.join(memDirAbs, relFs);
25108
+ const absTarget = path46.join(memDirAbs, relFs);
24600
25109
  const exists3 = await fileExists(absTarget);
24601
25110
  if (exists3) {
24602
25111
  if (conflict === "skip") {
@@ -24621,29 +25130,29 @@ async function importSqlite(opts) {
24621
25130
  }
24622
25131
  if (opts.dryRun) return { written: 0, skipped };
24623
25132
  for (const w of written) {
24624
- await mkdir31(path43.dirname(w.abs), { recursive: true });
24625
- await writeFile29(w.abs, w.content, "utf-8");
25133
+ await mkdir33(path46.dirname(w.abs), { recursive: true });
25134
+ await writeFile31(w.abs, w.content, "utf-8");
24626
25135
  }
24627
25136
  return { written: written.length, skipped };
24628
25137
  }
24629
25138
 
24630
25139
  // src/transfer/import-md.ts
24631
- import path44 from "path";
24632
- import { mkdir as mkdir32, readFile as readFile29, writeFile as writeFile30 } from "fs/promises";
25140
+ import path47 from "path";
25141
+ import { mkdir as mkdir34, readFile as readFile29, writeFile as writeFile32 } from "fs/promises";
24633
25142
  function normalizeForDedupe3(s) {
24634
25143
  return s.replace(/\s+/g, " ").trim();
24635
25144
  }
24636
25145
  async function importMarkdownBundle(opts) {
24637
25146
  const conflict = opts.conflict ?? "skip";
24638
- const fromAbs = path44.resolve(opts.fromDir);
24639
- const targetAbs = path44.resolve(opts.targetMemoryDir);
25147
+ const fromAbs = path47.resolve(opts.fromDir);
25148
+ const targetAbs = path47.resolve(opts.targetMemoryDir);
24640
25149
  const filesAbs = await listFilesRecursive(fromAbs);
24641
25150
  const writes = [];
24642
25151
  let skipped = 0;
24643
25152
  for (const abs of filesAbs) {
24644
25153
  const relPosix = toPosixRelPath(abs, fromAbs);
24645
25154
  if (relPosix === "manifest.json") continue;
24646
- const dstAbs = path44.join(targetAbs, fromPosixRelPath(relPosix));
25155
+ const dstAbs = path47.join(targetAbs, fromPosixRelPath(relPosix));
24647
25156
  const content = await readFile29(abs, "utf-8");
24648
25157
  const exists3 = await fileExists(dstAbs);
24649
25158
  if (exists3) {
@@ -24666,17 +25175,17 @@ async function importMarkdownBundle(opts) {
24666
25175
  }
24667
25176
  if (opts.dryRun) return { written: 0, skipped };
24668
25177
  for (const w of writes) {
24669
- await mkdir32(path44.dirname(w.abs), { recursive: true });
24670
- await writeFile30(w.abs, w.content, "utf-8");
25178
+ await mkdir34(path47.dirname(w.abs), { recursive: true });
25179
+ await writeFile32(w.abs, w.content, "utf-8");
24671
25180
  }
24672
25181
  return { written: writes.length, skipped };
24673
25182
  }
24674
25183
 
24675
25184
  // src/transfer/autodetect.ts
24676
- import path45 from "path";
25185
+ import path48 from "path";
24677
25186
  import { stat as stat9 } from "fs/promises";
24678
25187
  async function detectImportFormat(fromPath) {
24679
- const abs = path45.resolve(fromPath);
25188
+ const abs = path48.resolve(fromPath);
24680
25189
  let st;
24681
25190
  try {
24682
25191
  st = await stat9(abs);
@@ -25104,8 +25613,8 @@ function gatherCandidates(input, warnings) {
25104
25613
  const record = rec;
25105
25614
  const content = typeof record.content === "string" ? record.content : null;
25106
25615
  if (!content) continue;
25107
- const path58 = typeof record.path === "string" ? record.path : "";
25108
- if (!path58.startsWith("transcripts/") && !path58.includes("/transcripts/")) continue;
25616
+ const path59 = typeof record.path === "string" ? record.path : "";
25617
+ if (!path59.startsWith("transcripts/") && !path59.includes("/transcripts/")) continue;
25109
25618
  rows.push(...parseJsonl(content, warnings));
25110
25619
  }
25111
25620
  return rows;
@@ -25161,8 +25670,8 @@ var openclawReplayNormalizer = {
25161
25670
  };
25162
25671
 
25163
25672
  // src/maintenance/archive-observations.ts
25164
- import path46 from "path";
25165
- import { mkdir as mkdir33, readdir as readdir20, readFile as readFile30, unlink as unlink6, writeFile as writeFile31 } from "fs/promises";
25673
+ import path49 from "path";
25674
+ import { mkdir as mkdir35, readdir as readdir20, readFile as readFile30, unlink as unlink6, writeFile as writeFile33 } from "fs/promises";
25166
25675
  var DATE_FILE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})\.(jsonl|md)$/;
25167
25676
  function normalizeRetentionDays(value) {
25168
25677
  if (!Number.isFinite(value)) return 30;
@@ -25188,8 +25697,8 @@ async function listFilesRecursive2(root, relPrefix = "") {
25188
25697
  return out;
25189
25698
  }
25190
25699
  for (const entry of entries) {
25191
- const rel = relPrefix ? path46.join(relPrefix, entry.name) : entry.name;
25192
- const full = path46.join(root, entry.name);
25700
+ const rel = relPrefix ? path49.join(relPrefix, entry.name) : entry.name;
25701
+ const full = path49.join(root, entry.name);
25193
25702
  if (entry.isDirectory()) {
25194
25703
  out.push(...await listFilesRecursive2(full, rel));
25195
25704
  continue;
@@ -25199,19 +25708,19 @@ async function listFilesRecursive2(root, relPrefix = "") {
25199
25708
  return out;
25200
25709
  }
25201
25710
  async function collectArchiveCandidates(memoryDir, cutoffTimeMs) {
25202
- const roots = ["transcripts", path46.join("state", "tool-usage"), path46.join("summaries", "hourly")];
25711
+ const roots = ["transcripts", path49.join("state", "tool-usage"), path49.join("summaries", "hourly")];
25203
25712
  const out = [];
25204
25713
  for (const relRoot of roots) {
25205
- const absRoot = path46.join(memoryDir, relRoot);
25714
+ const absRoot = path49.join(memoryDir, relRoot);
25206
25715
  const files = await listFilesRecursive2(absRoot);
25207
25716
  for (const fileRel of files) {
25208
- const filename = path46.basename(fileRel);
25717
+ const filename = path49.basename(fileRel);
25209
25718
  const parsedDate = extractDateFromFilename(filename);
25210
25719
  if (!parsedDate) continue;
25211
25720
  if (parsedDate.getTime() >= cutoffTimeMs) continue;
25212
25721
  out.push({
25213
- absolutePath: path46.join(absRoot, fileRel),
25214
- relativePath: path46.join(relRoot, fileRel)
25722
+ absolutePath: path49.join(absRoot, fileRel),
25723
+ relativePath: path49.join(relRoot, fileRel)
25215
25724
  });
25216
25725
  }
25217
25726
  }
@@ -25226,7 +25735,7 @@ async function archiveObservations(options) {
25226
25735
  new Date(now.getTime() - retentionDays * 24 * 60 * 60 * 1e3)
25227
25736
  );
25228
25737
  const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
25229
- const archiveRoot = path46.join(options.memoryDir, "archive", "observations", stamp);
25738
+ const archiveRoot = path49.join(options.memoryDir, "archive", "observations", stamp);
25230
25739
  const candidates = retentionDays === 0 ? [] : await collectArchiveCandidates(
25231
25740
  options.memoryDir,
25232
25741
  cutoffDayStartUtc
@@ -25235,13 +25744,13 @@ async function archiveObservations(options) {
25235
25744
  let archivedBytes = 0;
25236
25745
  const archivedRelativePaths = [];
25237
25746
  if (!dryRun && candidates.length > 0) {
25238
- await mkdir33(archiveRoot, { recursive: true });
25747
+ await mkdir35(archiveRoot, { recursive: true });
25239
25748
  for (const candidate of candidates) {
25240
- const archivePath = path46.join(archiveRoot, candidate.relativePath);
25241
- const archiveDir = path46.dirname(archivePath);
25242
- await mkdir33(archiveDir, { recursive: true });
25749
+ const archivePath = path49.join(archiveRoot, candidate.relativePath);
25750
+ const archiveDir = path49.dirname(archivePath);
25751
+ await mkdir35(archiveDir, { recursive: true });
25243
25752
  const raw = await readFile30(candidate.absolutePath);
25244
- await writeFile31(archivePath, raw);
25753
+ await writeFile33(archivePath, raw);
25245
25754
  await unlink6(candidate.absolutePath);
25246
25755
  archivedFiles += 1;
25247
25756
  archivedBytes += raw.byteLength;
@@ -25262,12 +25771,12 @@ async function archiveObservations(options) {
25262
25771
  }
25263
25772
 
25264
25773
  // src/maintenance/rebuild-observations.ts
25265
- import path48 from "path";
25774
+ import path51 from "path";
25266
25775
  import { readdir as readdir21, readFile as readFile32 } from "fs/promises";
25267
25776
 
25268
25777
  // src/maintenance/observation-ledger-utils.ts
25269
- import path47 from "path";
25270
- import { mkdir as mkdir34, readFile as readFile31, writeFile as writeFile32 } from "fs/promises";
25778
+ import path50 from "path";
25779
+ import { mkdir as mkdir36, readFile as readFile31, writeFile as writeFile34 } from "fs/promises";
25271
25780
  function toHourBucketIso(timestamp) {
25272
25781
  const normalized = /(?:Z|[+-]\d{2}:\d{2})$/u.test(timestamp) ? timestamp : `${timestamp}Z`;
25273
25782
  const ms = Date.parse(normalized);
@@ -25278,8 +25787,8 @@ function toHourBucketIso(timestamp) {
25278
25787
  }
25279
25788
  async function backupAndWriteRebuiltObservations(options) {
25280
25789
  const stamp = options.now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
25281
- const archiveRoot = path47.join(options.memoryDir, "archive", "observations", stamp);
25282
- let backupPath = path47.join(
25790
+ const archiveRoot = path50.join(options.memoryDir, "archive", "observations", stamp);
25791
+ let backupPath = path50.join(
25283
25792
  archiveRoot,
25284
25793
  "state",
25285
25794
  "observation-ledger",
@@ -25287,8 +25796,8 @@ async function backupAndWriteRebuiltObservations(options) {
25287
25796
  );
25288
25797
  try {
25289
25798
  const existing = await readFile31(options.outputPath, "utf-8");
25290
- await mkdir34(path47.dirname(backupPath), { recursive: true });
25291
- await writeFile32(backupPath, existing, "utf-8");
25799
+ await mkdir36(path50.dirname(backupPath), { recursive: true });
25800
+ await writeFile34(backupPath, existing, "utf-8");
25292
25801
  } catch (err) {
25293
25802
  const code = err.code;
25294
25803
  if (code && code === "ENOENT") {
@@ -25304,8 +25813,8 @@ async function backupAndWriteRebuiltObservations(options) {
25304
25813
  rebuiltAt
25305
25814
  })
25306
25815
  );
25307
- await mkdir34(path47.dirname(options.outputPath), { recursive: true });
25308
- await writeFile32(options.outputPath, lines.length > 0 ? `${lines.join("\n")}
25816
+ await mkdir36(path50.dirname(options.outputPath), { recursive: true });
25817
+ await writeFile34(options.outputPath, lines.length > 0 ? `${lines.join("\n")}
25309
25818
  ` : "", "utf-8");
25310
25819
  return backupPath;
25311
25820
  }
@@ -25327,7 +25836,7 @@ async function listTranscriptFiles2(root) {
25327
25836
  for (const entry of entries) {
25328
25837
  if (entry.name === "." || entry.name === "..") continue;
25329
25838
  if (entry.isSymbolicLink()) continue;
25330
- const full = path48.join(root, entry.name);
25839
+ const full = path51.join(root, entry.name);
25331
25840
  if (entry.isDirectory()) {
25332
25841
  out.push(...await listTranscriptFiles2(full));
25333
25842
  continue;
@@ -25387,8 +25896,8 @@ function buildLedgerRows(linesByFile) {
25387
25896
  async function rebuildObservations(options) {
25388
25897
  const dryRun = options.dryRun !== false;
25389
25898
  const now = options.now ?? /* @__PURE__ */ new Date();
25390
- const transcriptsRoot = path48.join(options.memoryDir, "transcripts");
25391
- const outputPath = path48.join(
25899
+ const transcriptsRoot = path51.join(options.memoryDir, "transcripts");
25900
+ const outputPath = path51.join(
25392
25901
  options.memoryDir,
25393
25902
  "state",
25394
25903
  "observation-ledger",
@@ -25424,7 +25933,7 @@ async function rebuildObservations(options) {
25424
25933
  }
25425
25934
 
25426
25935
  // src/maintenance/migrate-observations.ts
25427
- import path49 from "path";
25936
+ import path52 from "path";
25428
25937
  import { readdir as readdir22, readFile as readFile33 } from "fs/promises";
25429
25938
  function toNonNegativeInt(value) {
25430
25939
  if (typeof value !== "number" || !Number.isFinite(value)) return null;
@@ -25488,15 +25997,15 @@ async function listLegacyObservationFiles(root) {
25488
25997
  async function migrateObservations(options) {
25489
25998
  const dryRun = options.dryRun !== false;
25490
25999
  const now = options.now ?? /* @__PURE__ */ new Date();
25491
- const ledgerRoot = path49.join(options.memoryDir, "state", "observation-ledger");
25492
- const outputPath = path49.join(ledgerRoot, "rebuilt-observations.jsonl");
26000
+ const ledgerRoot = path52.join(options.memoryDir, "state", "observation-ledger");
26001
+ const outputPath = path52.join(ledgerRoot, "rebuilt-observations.jsonl");
25493
26002
  const legacyFiles = await listLegacyObservationFiles(ledgerRoot);
25494
- const sourceRelativePaths = legacyFiles.map((name) => path49.join("state", "observation-ledger", name));
26003
+ const sourceRelativePaths = legacyFiles.map((name) => path52.join("state", "observation-ledger", name));
25495
26004
  const byKey = /* @__PURE__ */ new Map();
25496
26005
  let parsedRows = 0;
25497
26006
  let malformedLines = 0;
25498
26007
  for (const file of legacyFiles) {
25499
- const full = path49.join(ledgerRoot, file);
26008
+ const full = path52.join(ledgerRoot, file);
25500
26009
  const raw = await readFile33(full, "utf-8");
25501
26010
  for (const line of raw.split("\n")) {
25502
26011
  if (!line.trim()) continue;
@@ -25686,10 +26195,10 @@ var defaultCommandRunner = (command, args, options) => {
25686
26195
 
25687
26196
  // src/network/webdav.ts
25688
26197
  import { createReadStream } from "fs";
25689
- import { mkdir as mkdir35, readdir as readdir23, realpath as realpath2, stat as stat11 } from "fs/promises";
26198
+ import { mkdir as mkdir37, readdir as readdir23, realpath as realpath2, stat as stat11 } from "fs/promises";
25690
26199
  import { createServer } from "http";
25691
26200
  import { timingSafeEqual } from "crypto";
25692
- import path50 from "path";
26201
+ import path53 from "path";
25693
26202
  import { pipeline } from "stream/promises";
25694
26203
  import { URL as URL2 } from "url";
25695
26204
  function hostToUrlAuthority(host) {
@@ -25725,10 +26234,10 @@ var WebDavServer = class _WebDavServer {
25725
26234
  const allowedRoots = [];
25726
26235
  const aliasSet = /* @__PURE__ */ new Set();
25727
26236
  for (const dir of options.allowlistDirs) {
25728
- const resolved = path50.resolve(dir);
25729
- await mkdir35(resolved, { recursive: true });
26237
+ const resolved = path53.resolve(dir);
26238
+ await mkdir37(resolved, { recursive: true });
25730
26239
  const canonical = await realpath2(resolved);
25731
- const alias = path50.basename(canonical) || "root";
26240
+ const alias = path53.basename(canonical) || "root";
25732
26241
  if (aliasSet.has(alias)) {
25733
26242
  throw new Error(`duplicate webdav allowlist alias: ${alias}`);
25734
26243
  }
@@ -25884,7 +26393,7 @@ var WebDavServer = class _WebDavServer {
25884
26393
  if (decodedPath.includes("\0")) {
25885
26394
  return { ok: false, code: 400, message: "invalid path" };
25886
26395
  }
25887
- const normalized = path50.posix.normalize(decodedPath);
26396
+ const normalized = path53.posix.normalize(decodedPath);
25888
26397
  const segments = normalized.split("/").filter((segment) => segment.length > 0);
25889
26398
  if (segments.length === 0) {
25890
26399
  return { ok: false, code: 403, message: "root listing is not allowed" };
@@ -25898,7 +26407,7 @@ var WebDavServer = class _WebDavServer {
25898
26407
  if (relative.some((segment) => segment === ".." || segment.includes("\\"))) {
25899
26408
  return { ok: false, code: 403, message: "path traversal is not allowed" };
25900
26409
  }
25901
- const candidate = path50.resolve(root.absolute, ...relative);
26410
+ const candidate = path53.resolve(root.absolute, ...relative);
25902
26411
  if (!this.isPathInside(root.absolute, candidate)) {
25903
26412
  return { ok: false, code: 403, message: "path escaped allowlist" };
25904
26413
  }
@@ -25976,10 +26485,10 @@ var WebDavServer = class _WebDavServer {
25976
26485
  }
25977
26486
  isPathInside(root, target) {
25978
26487
  if (target === root) return true;
25979
- if (root === path50.parse(root).root) {
26488
+ if (root === path53.parse(root).root) {
25980
26489
  return target.startsWith(root);
25981
26490
  }
25982
- return target.startsWith(`${root}${path50.sep}`);
26491
+ return target.startsWith(`${root}${path53.sep}`);
25983
26492
  }
25984
26493
  };
25985
26494
  function xmlEscape(value) {
@@ -25994,10 +26503,10 @@ import { createHash as createHash9 } from "crypto";
25994
26503
  import { createServer as createServer2 } from "http";
25995
26504
  import { watch } from "fs";
25996
26505
  import { readFile as readFile35 } from "fs/promises";
25997
- import path52 from "path";
26506
+ import path55 from "path";
25998
26507
 
25999
26508
  // src/graph-dashboard-parser.ts
26000
- import path51 from "path";
26509
+ import path54 from "path";
26001
26510
  import { readFile as readFile34 } from "fs/promises";
26002
26511
 
26003
26512
  // src/graph-dashboard-key.ts
@@ -26008,7 +26517,7 @@ function graphEdgeKey(edge) {
26008
26517
  // src/graph-dashboard-parser.ts
26009
26518
  var GRAPH_TYPES = ["entity", "time", "causal"];
26010
26519
  function graphFile(memoryDir, type) {
26011
- return path51.join(memoryDir, "state", "graphs", `${type}.jsonl`);
26520
+ return path54.join(memoryDir, "state", "graphs", `${type}.jsonl`);
26012
26521
  }
26013
26522
  function isGraphEdge(raw, expectedType) {
26014
26523
  if (!raw || typeof raw !== "object") return false;
@@ -26135,7 +26644,7 @@ var GraphDashboardServer = class {
26135
26644
  this.memoryDir = options.memoryDir;
26136
26645
  this.host = options.host?.trim() || "127.0.0.1";
26137
26646
  this.requestedPort = Number.isFinite(options.port) ? Math.max(0, Math.floor(options.port ?? 0)) : 0;
26138
- this.publicDir = options.publicDir ?? path52.join(process.cwd(), "dashboard", "public");
26647
+ this.publicDir = options.publicDir ?? path55.join(process.cwd(), "dashboard", "public");
26139
26648
  this.watchDebounceMs = Math.max(50, Math.floor(options.watchDebounceMs ?? 300));
26140
26649
  }
26141
26650
  async start() {
@@ -26234,11 +26743,11 @@ var GraphDashboardServer = class {
26234
26743
  return;
26235
26744
  }
26236
26745
  if (req.method === "GET" && url === "/app.js") {
26237
- await this.respondStatic(res, path52.join(this.publicDir, "app.js"), "application/javascript; charset=utf-8");
26746
+ await this.respondStatic(res, path55.join(this.publicDir, "app.js"), "application/javascript; charset=utf-8");
26238
26747
  return;
26239
26748
  }
26240
26749
  if (req.method === "GET" && (url === "/" || url === "/index.html")) {
26241
- await this.respondStatic(res, path52.join(this.publicDir, "index.html"), "text/html; charset=utf-8");
26750
+ await this.respondStatic(res, path55.join(this.publicDir, "index.html"), "text/html; charset=utf-8");
26242
26751
  return;
26243
26752
  }
26244
26753
  this.respondJson(res, 404, { error: "Not found" });
@@ -26324,7 +26833,7 @@ var GraphDashboardServer = class {
26324
26833
  }
26325
26834
  }
26326
26835
  startWatcher() {
26327
- const graphDir = path52.join(this.memoryDir, "state", "graphs");
26836
+ const graphDir = path55.join(this.memoryDir, "state", "graphs");
26328
26837
  try {
26329
26838
  this.watcher = watch(graphDir, { persistent: false }, () => {
26330
26839
  this.scheduleRebuild();
@@ -26370,7 +26879,7 @@ var GraphDashboardServer = class {
26370
26879
 
26371
26880
  // src/compat/checks.ts
26372
26881
  import { access as access2, readFile as readFile36 } from "fs/promises";
26373
- import path53 from "path";
26882
+ import path56 from "path";
26374
26883
  import { spawn as spawn4 } from "child_process";
26375
26884
  var REQUIRED_HOOKS = ["before_agent_start", "agent_end"];
26376
26885
  function isSafeCommandToken(command) {
@@ -26552,9 +27061,9 @@ function compareVersions(a, b) {
26552
27061
  async function runCompatChecks(options) {
26553
27062
  const checks = [];
26554
27063
  const runner = options.runner ?? defaultRunner;
26555
- const pluginJsonPath = path53.join(options.repoRoot, "openclaw.plugin.json");
26556
- const packageJsonPath = path53.join(options.repoRoot, "package.json");
26557
- const indexPath = path53.join(options.repoRoot, "src", "index.ts");
27064
+ const pluginJsonPath = path56.join(options.repoRoot, "openclaw.plugin.json");
27065
+ const packageJsonPath = path56.join(options.repoRoot, "package.json");
27066
+ const indexPath = path56.join(options.repoRoot, "src", "index.ts");
26558
27067
  let pluginRaw = "";
26559
27068
  let pluginManifestPresent = false;
26560
27069
  try {
@@ -26739,171 +27248,6 @@ async function runCompatChecks(options) {
26739
27248
  };
26740
27249
  }
26741
27250
 
26742
- // src/abstraction-nodes.ts
26743
- import path54 from "path";
26744
- import { mkdir as mkdir36, writeFile as writeFile33 } from "fs/promises";
26745
- function validateKind2(raw) {
26746
- const value = assertString2(raw, "kind");
26747
- if (!["episode", "topic", "project", "workflow", "constraint"].includes(value)) {
26748
- throw new Error("kind must be one of episode|topic|project|workflow|constraint");
26749
- }
26750
- return value;
26751
- }
26752
- function validateLevel(raw) {
26753
- const value = assertString2(raw, "abstractionLevel");
26754
- if (!["micro", "meso", "macro"].includes(value)) {
26755
- throw new Error("abstractionLevel must be one of micro|meso|macro");
26756
- }
26757
- return value;
26758
- }
26759
- function resolveAbstractionNodeStoreDir(memoryDir, overrideDir) {
26760
- if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
26761
- return overrideDir.trim();
26762
- }
26763
- return path54.join(memoryDir, "state", "abstraction-nodes");
26764
- }
26765
- function validateAbstractionNode(raw) {
26766
- if (!isRecord2(raw)) throw new Error("abstraction node must be an object");
26767
- if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
26768
- return {
26769
- schemaVersion: 1,
26770
- nodeId: assertSafePathSegment(assertString2(raw.nodeId, "nodeId"), "nodeId"),
26771
- recordedAt: assertIsoRecordedAt(assertString2(raw.recordedAt, "recordedAt")),
26772
- sessionKey: assertString2(raw.sessionKey, "sessionKey"),
26773
- kind: validateKind2(raw.kind),
26774
- abstractionLevel: validateLevel(raw.abstractionLevel),
26775
- title: assertString2(raw.title, "title"),
26776
- summary: assertString2(raw.summary, "summary"),
26777
- sourceMemoryIds: optionalStringArray2(raw.sourceMemoryIds, "sourceMemoryIds"),
26778
- entityRefs: optionalStringArray2(raw.entityRefs, "entityRefs"),
26779
- tags: optionalStringArray2(raw.tags, "tags"),
26780
- metadata: validateStringRecord(raw.metadata, "metadata")
26781
- };
26782
- }
26783
- async function getAbstractionNodeStoreStatus(options) {
26784
- const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
26785
- const nodesDir = path54.join(rootDir, "nodes");
26786
- const files = await listJsonFiles(nodesDir);
26787
- const nodes = [];
26788
- const invalidNodes = [];
26789
- for (const filePath of files) {
26790
- try {
26791
- nodes.push(validateAbstractionNode(await readJsonFile(filePath)));
26792
- } catch (error) {
26793
- invalidNodes.push({
26794
- path: filePath,
26795
- error: error instanceof Error ? error.message : String(error)
26796
- });
26797
- }
26798
- }
26799
- nodes.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
26800
- const byKind = {};
26801
- const byLevel = {};
26802
- for (const node of nodes) {
26803
- byKind[node.kind] = (byKind[node.kind] ?? 0) + 1;
26804
- byLevel[node.abstractionLevel] = (byLevel[node.abstractionLevel] ?? 0) + 1;
26805
- }
26806
- return {
26807
- enabled: options.enabled,
26808
- anchorsEnabled: options.anchorsEnabled,
26809
- rootDir,
26810
- nodesDir,
26811
- nodes: {
26812
- total: files.length,
26813
- valid: nodes.length,
26814
- invalid: invalidNodes.length,
26815
- byKind,
26816
- byLevel,
26817
- latestNodeId: nodes[0]?.nodeId,
26818
- latestRecordedAt: nodes[0]?.recordedAt,
26819
- latestSessionKey: nodes[0]?.sessionKey
26820
- },
26821
- latestNode: nodes[0],
26822
- invalidNodes
26823
- };
26824
- }
26825
-
26826
- // src/cue-anchors.ts
26827
- import path55 from "path";
26828
- import { mkdir as mkdir37, writeFile as writeFile34 } from "fs/promises";
26829
- function validateAnchorType(raw) {
26830
- const value = assertString2(raw, "anchorType");
26831
- if (!["entity", "file", "tool", "outcome", "constraint", "date"].includes(value)) {
26832
- throw new Error("anchorType must be one of entity|file|tool|outcome|constraint|date");
26833
- }
26834
- return value;
26835
- }
26836
- function validateNodeRefs(raw) {
26837
- const nodeRefs = optionalStringArray2(raw, "nodeRefs");
26838
- if (!nodeRefs || nodeRefs.length === 0) {
26839
- throw new Error("nodeRefs must contain at least one node reference");
26840
- }
26841
- return nodeRefs.map((nodeRef, index) => assertSafePathSegment(nodeRef, `nodeRefs[${index}]`));
26842
- }
26843
- function resolveCueAnchorStoreDir(abstractionNodeStoreDir, overrideDir) {
26844
- if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
26845
- return overrideDir.trim();
26846
- }
26847
- return path55.join(abstractionNodeStoreDir, "anchors");
26848
- }
26849
- function validateCueAnchor(raw) {
26850
- if (!isRecord2(raw)) throw new Error("cue anchor must be an object");
26851
- if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
26852
- return {
26853
- schemaVersion: 1,
26854
- anchorId: assertSafePathSegment(assertString2(raw.anchorId, "anchorId"), "anchorId"),
26855
- anchorType: validateAnchorType(raw.anchorType),
26856
- anchorValue: assertString2(raw.anchorValue, "anchorValue"),
26857
- normalizedCue: assertString2(raw.normalizedCue, "normalizedCue"),
26858
- recordedAt: assertIsoRecordedAt(assertString2(raw.recordedAt, "recordedAt")),
26859
- sessionKey: assertString2(raw.sessionKey, "sessionKey"),
26860
- nodeRefs: validateNodeRefs(raw.nodeRefs),
26861
- tags: optionalStringArray2(raw.tags, "tags"),
26862
- metadata: validateStringRecord(raw.metadata, "metadata")
26863
- };
26864
- }
26865
- async function getCueAnchorStoreStatus(options) {
26866
- const abstractionNodeStoreDir = options.abstractionNodeStoreDir?.trim().length ? options.abstractionNodeStoreDir.trim() : path55.join(options.memoryDir, "state", "abstraction-nodes");
26867
- const rootDir = resolveCueAnchorStoreDir(abstractionNodeStoreDir, options.cueAnchorStoreDir);
26868
- const files = await listJsonFiles(rootDir);
26869
- const anchors = [];
26870
- const invalidAnchors = [];
26871
- for (const filePath of files) {
26872
- try {
26873
- anchors.push(validateCueAnchor(await readJsonFile(filePath)));
26874
- } catch (error) {
26875
- invalidAnchors.push({
26876
- path: filePath,
26877
- error: error instanceof Error ? error.message : String(error)
26878
- });
26879
- }
26880
- }
26881
- anchors.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
26882
- const byType = {};
26883
- let totalNodeRefs = 0;
26884
- for (const anchor of anchors) {
26885
- byType[anchor.anchorType] = (byType[anchor.anchorType] ?? 0) + 1;
26886
- totalNodeRefs += anchor.nodeRefs.length;
26887
- }
26888
- return {
26889
- enabled: options.enabled,
26890
- anchorsEnabled: options.anchorsEnabled,
26891
- rootDir,
26892
- anchors: {
26893
- total: files.length,
26894
- valid: anchors.length,
26895
- invalid: invalidAnchors.length,
26896
- byType,
26897
- totalNodeRefs,
26898
- latestAnchorId: anchors[0]?.anchorId,
26899
- latestRecordedAt: anchors[0]?.recordedAt,
26900
- latestSessionKey: anchors[0]?.sessionKey
26901
- },
26902
- latestAnchor: anchors[0],
26903
- invalidAnchors
26904
- };
26905
- }
26906
-
26907
27251
  // src/cli.ts
26908
27252
  function rankCandidateForKeep(a, b) {
26909
27253
  const aConfidence = typeof a.frontmatter.confidence === "number" ? a.frontmatter.confidence : 0;
@@ -27129,6 +27473,26 @@ async function runCueAnchorStatusCliCommand(options) {
27129
27473
  anchorsEnabled: options.abstractionAnchorsEnabled
27130
27474
  });
27131
27475
  }
27476
+ async function runHarmonicSearchCliCommand(options) {
27477
+ if (!options.harmonicRetrievalEnabled) return [];
27478
+ return searchHarmonicRetrieval({
27479
+ memoryDir: options.memoryDir,
27480
+ abstractionNodeStoreDir: options.abstractionNodeStoreDir,
27481
+ query: options.query,
27482
+ maxResults: Math.max(1, Math.floor(options.maxResults ?? 3)),
27483
+ sessionKey: options.sessionKey,
27484
+ anchorsEnabled: options.abstractionAnchorsEnabled
27485
+ });
27486
+ }
27487
+ async function runVerifiedRecallSearchCliCommand(options) {
27488
+ if (!options.verifiedRecallEnabled) return [];
27489
+ return searchVerifiedEpisodes({
27490
+ memoryDir: options.memoryDir,
27491
+ query: options.query,
27492
+ maxResults: Math.max(1, Math.floor(options.maxResults ?? 3)),
27493
+ boxRecallDays: options.boxRecallDays
27494
+ });
27495
+ }
27132
27496
  async function runTrustZonePromoteCliCommand(options) {
27133
27497
  const result = await promoteTrustZoneRecord({
27134
27498
  memoryDir: options.memoryDir,
@@ -27375,7 +27739,7 @@ function policyVersionForValues(values, config) {
27375
27739
  return createHash10("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 12);
27376
27740
  }
27377
27741
  async function readRuntimePolicySnapshot2(config, fileName) {
27378
- const filePath = path56.join(config.memoryDir, "state", fileName);
27742
+ const filePath = path57.join(config.memoryDir, "state", fileName);
27379
27743
  const snapshot = await readRuntimePolicySnapshot(filePath, {
27380
27744
  maxStaleDecayThreshold: config.lifecycleArchiveDecayThreshold
27381
27745
  });
@@ -27959,14 +28323,14 @@ async function resolveMemoryDirForNamespace(orchestrator, namespace) {
27959
28323
  const ns = (namespace ?? "").trim();
27960
28324
  if (!ns) return orchestrator.config.memoryDir;
27961
28325
  if (!orchestrator.config.namespacesEnabled) return orchestrator.config.memoryDir;
27962
- const candidate = path56.join(orchestrator.config.memoryDir, "namespaces", ns);
28326
+ const candidate = path57.join(orchestrator.config.memoryDir, "namespaces", ns);
27963
28327
  if (ns === orchestrator.config.defaultNamespace) {
27964
28328
  return await exists2(candidate) ? candidate : orchestrator.config.memoryDir;
27965
28329
  }
27966
28330
  return candidate;
27967
28331
  }
27968
28332
  async function readAllMemoryFiles(memoryDir) {
27969
- const roots = [path56.join(memoryDir, "facts"), path56.join(memoryDir, "corrections")];
28333
+ const roots = [path57.join(memoryDir, "facts"), path57.join(memoryDir, "corrections")];
27970
28334
  const out = [];
27971
28335
  const walk = async (dir) => {
27972
28336
  let entries;
@@ -27977,7 +28341,7 @@ async function readAllMemoryFiles(memoryDir) {
27977
28341
  }
27978
28342
  for (const entry of entries) {
27979
28343
  const entryName = typeof entry.name === "string" ? entry.name : entry.name.toString("utf-8");
27980
- const fullPath = path56.join(dir, entryName);
28344
+ const fullPath = path57.join(dir, entryName);
27981
28345
  if (entry.isDirectory()) {
27982
28346
  await walk(fullPath);
27983
28347
  continue;
@@ -28340,6 +28704,22 @@ function registerCli(api, orchestrator) {
28340
28704
  console.log(JSON.stringify(status, null, 2));
28341
28705
  console.log("OK");
28342
28706
  });
28707
+ cmd.command("harmonic-search").description("Preview harmonic retrieval blending over abstraction nodes and cue anchors").argument("<query>", "Prompt-like query to evaluate against harmonic retrieval storage").option("--max-results <count>", "Maximum number of blended results to return", "3").option("--session-key <sessionKey>", "Optional session key for same-session tie-breaking").action(async (...args) => {
28708
+ const query = typeof args[0] === "string" ? args[0] : "";
28709
+ const options = args[1] ?? {};
28710
+ const maxResults = typeof options.maxResults === "string" ? Number.parseInt(options.maxResults, 10) : 3;
28711
+ const results = await runHarmonicSearchCliCommand({
28712
+ memoryDir: orchestrator.config.memoryDir,
28713
+ abstractionNodeStoreDir: orchestrator.config.abstractionNodeStoreDir,
28714
+ harmonicRetrievalEnabled: orchestrator.config.harmonicRetrievalEnabled,
28715
+ abstractionAnchorsEnabled: orchestrator.config.abstractionAnchorsEnabled,
28716
+ query,
28717
+ maxResults: Number.isFinite(maxResults) ? maxResults : 3,
28718
+ sessionKey: typeof options.sessionKey === "string" ? options.sessionKey : void 0
28719
+ });
28720
+ console.log(JSON.stringify(results, null, 2));
28721
+ console.log("OK");
28722
+ });
28343
28723
  cmd.command("trust-zone-promote").description("Dry-run or apply a trust-zone promotion with provenance enforcement").requiredOption("--record-id <recordId>", "Source trust-zone record id").requiredOption("--target-zone <targetZone>", "Promotion target zone (working|trusted)").requiredOption("--reason <reason>", "Human-readable promotion reason").option("--recorded-at <isoTimestamp>", "Promotion timestamp (defaults to now)").option("--summary <summary>", "Optional replacement summary for the promoted record").option("--dry-run", "Show the promotion plan without writing the promoted record").action(async (...args) => {
28344
28724
  const options = args[0] ?? {};
28345
28725
  const result = await runTrustZonePromoteCliCommand({
@@ -28358,6 +28738,20 @@ function registerCli(api, orchestrator) {
28358
28738
  console.log(JSON.stringify(result, null, 2));
28359
28739
  console.log("OK");
28360
28740
  });
28741
+ cmd.command("verified-recall-search").description("Preview verified episodic recall over recent memory boxes").argument("<query>", "Prompt-like query to evaluate against verified episodic recall").option("--max-results <count>", "Maximum number of verified episodic results to return", "3").action(async (...args) => {
28742
+ const query = typeof args[0] === "string" ? args[0] : "";
28743
+ const options = args[1] ?? {};
28744
+ const maxResults = typeof options.maxResults === "string" ? Number.parseInt(options.maxResults, 10) : 3;
28745
+ const results = await runVerifiedRecallSearchCliCommand({
28746
+ memoryDir: orchestrator.config.memoryDir,
28747
+ verifiedRecallEnabled: orchestrator.config.verifiedRecallEnabled,
28748
+ query,
28749
+ maxResults: Number.isFinite(maxResults) ? maxResults : 3,
28750
+ boxRecallDays: orchestrator.config.boxRecallDays
28751
+ });
28752
+ console.log(JSON.stringify(results, null, 2));
28753
+ console.log("OK");
28754
+ });
28361
28755
  cmd.command("conversation-index-health").description("Show conversation index backend health and index stats").action(async () => {
28362
28756
  const health = await runConversationIndexHealthCliCommand(orchestrator);
28363
28757
  console.log(JSON.stringify(health, null, 2));
@@ -29007,7 +29401,7 @@ function registerCli(api, orchestrator) {
29007
29401
  }
29008
29402
  });
29009
29403
  cmd.command("identity").description("Show agent identity reflections").action(async () => {
29010
- const workspaceDir = path56.join(process.env.HOME ?? "~", ".openclaw", "workspace");
29404
+ const workspaceDir = path57.join(process.env.HOME ?? "~", ".openclaw", "workspace");
29011
29405
  const identity = await orchestrator.storage.readIdentity(workspaceDir);
29012
29406
  if (!identity) {
29013
29407
  console.log("No identity file found.");
@@ -29230,8 +29624,8 @@ function registerCli(api, orchestrator) {
29230
29624
  const options = args[0] ?? {};
29231
29625
  const threadId = options.thread;
29232
29626
  const top = parseInt(options.top ?? "10", 10);
29233
- const memoryDir = path56.join(process.env.HOME ?? "~", ".openclaw", "workspace", "memory", "local");
29234
- const threading = new ThreadingManager(path56.join(memoryDir, "threads"));
29627
+ const memoryDir = path57.join(process.env.HOME ?? "~", ".openclaw", "workspace", "memory", "local");
29628
+ const threading = new ThreadingManager(path57.join(memoryDir, "threads"));
29235
29629
  if (threadId) {
29236
29630
  const thread = await threading.loadThread(threadId);
29237
29631
  if (!thread) {
@@ -29709,7 +30103,7 @@ async function recordObjectiveStateSnapshotsFromAgentMessages(options) {
29709
30103
  // src/index.ts
29710
30104
  import { readFile as readFile38, writeFile as writeFile35 } from "fs/promises";
29711
30105
  import { readFileSync as readFileSync4 } from "fs";
29712
- import path57 from "path";
30106
+ import path58 from "path";
29713
30107
  import os6 from "os";
29714
30108
  var ENGRAM_REGISTERED_GUARD = "__openclawEngramRegistered";
29715
30109
  var ENGRAM_HOOK_APIS = "__openclawEngramHookApis";
@@ -29717,7 +30111,7 @@ function loadPluginConfigFromFile() {
29717
30111
  try {
29718
30112
  const explicitConfigPath = process.env.OPENCLAW_ENGRAM_CONFIG_PATH || process.env.OPENCLAW_CONFIG_PATH;
29719
30113
  const homeDir = process.env.HOME ?? os6.homedir();
29720
- const configPath = explicitConfigPath && explicitConfigPath.length > 0 ? explicitConfigPath : path57.join(homeDir, ".openclaw", "openclaw.json");
30114
+ const configPath = explicitConfigPath && explicitConfigPath.length > 0 ? explicitConfigPath : path58.join(homeDir, ".openclaw", "openclaw.json");
29721
30115
  const content = readFileSync4(configPath, "utf-8");
29722
30116
  const config = JSON.parse(content);
29723
30117
  const pluginEntry = config?.plugins?.entries?.["openclaw-engram"];
@@ -29967,7 +30361,7 @@ Use this context naturally when relevant. Never quote or expose this memory cont
29967
30361
  `session reset via API for ${sessionKey}, new sessionId=${result.sessionId}`
29968
30362
  );
29969
30363
  const safeSessionKey = sanitizeSessionKeyForFilename(sessionKey);
29970
- const signalPath = path57.join(
30364
+ const signalPath = path58.join(
29971
30365
  workspaceDir,
29972
30366
  `.compaction-reset-signal-${safeSessionKey}`
29973
30367
  );
@@ -29998,7 +30392,7 @@ Use this context naturally when relevant. Never quote or expose this memory cont
29998
30392
  );
29999
30393
  async function ensureHourlySummaryCron(api2) {
30000
30394
  const jobId = "engram-hourly-summary";
30001
- const cronFilePath = path57.join(os6.homedir(), ".openclaw", "cron", "jobs.json");
30395
+ const cronFilePath = path58.join(os6.homedir(), ".openclaw", "cron", "jobs.json");
30002
30396
  try {
30003
30397
  let jobsData = { version: 1, jobs: [] };
30004
30398
  try {