@joshuaswarren/openclaw-engram 8.0.3 → 8.0.4

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
@@ -368,12 +368,15 @@ function parseConfig(raw) {
368
368
  traceWeaverOverlapThreshold: typeof cfg.traceWeaverOverlapThreshold === "number" ? cfg.traceWeaverOverlapThreshold : 0.4,
369
369
  boxRecallDays: typeof cfg.boxRecallDays === "number" ? cfg.boxRecallDays : 3,
370
370
  // v8.0 Phase 2B: Episode/Note dual store (HiMem)
371
- episodeNoteModeEnabled: cfg.episodeNoteModeEnabled === true
371
+ episodeNoteModeEnabled: cfg.episodeNoteModeEnabled === true,
372
+ // v8.1: Temporal + Tag Indexes (SwiftMem-inspired)
373
+ queryAwareIndexingEnabled: cfg.queryAwareIndexingEnabled === true,
374
+ queryAwareIndexingMaxCandidates: typeof cfg.queryAwareIndexingMaxCandidates === "number" ? Math.max(0, cfg.queryAwareIndexingMaxCandidates) : 200
372
375
  };
373
376
  }
374
377
 
375
378
  // src/orchestrator.ts
376
- import path19 from "path";
379
+ import path20 from "path";
377
380
  import { createHash as createHash4 } from "crypto";
378
381
  import { mkdir as mkdir14, readFile as readFile14, writeFile as writeFile14 } from "fs/promises";
379
382
 
@@ -1101,8 +1104,8 @@ var LocalLlmClient = class _LocalLlmClient {
1101
1104
  log.debug(`local LLM: request body length=${requestBodyJson.length}`);
1102
1105
  if (this.config.debug) {
1103
1106
  try {
1104
- const { writeFileSync: writeFileSync2 } = await import("fs");
1105
- writeFileSync2("/tmp/engram-last-request.json", requestBodyJson);
1107
+ const { writeFileSync: writeFileSync3 } = await import("fs");
1108
+ writeFileSync3("/tmp/engram-last-request.json", requestBodyJson);
1106
1109
  } catch {
1107
1110
  }
1108
1111
  }
@@ -4300,8 +4303,8 @@ var ContentHashIndex = class _ContentHashIndex {
4300
4303
  hashes = /* @__PURE__ */ new Set();
4301
4304
  dirty = false;
4302
4305
  filePath;
4303
- constructor(stateDir) {
4304
- this.filePath = path4.join(stateDir, "fact-hashes.txt");
4306
+ constructor(stateDir2) {
4307
+ this.filePath = path4.join(stateDir2, "fact-hashes.txt");
4305
4308
  }
4306
4309
  /** Load existing hashes from disk. Safe to call multiple times. */
4307
4310
  async load() {
@@ -4998,23 +5001,23 @@ ${sanitized.text}
4998
5001
  async cleanExpiredTTL() {
4999
5002
  const memories = await this.readAllMemories();
5000
5003
  const now = Date.now();
5001
- let cleaned = 0;
5004
+ const deleted = [];
5002
5005
  for (const m of memories) {
5003
5006
  if (!m.frontmatter.expiresAt) continue;
5004
5007
  const expiresAt = new Date(m.frontmatter.expiresAt).getTime();
5005
5008
  if (expiresAt < now) {
5006
5009
  try {
5007
5010
  await unlink(m.path);
5008
- cleaned++;
5011
+ deleted.push(m);
5009
5012
  log.debug(`cleaned expired memory ${m.frontmatter.id} (TTL expired)`);
5010
5013
  } catch {
5011
5014
  }
5012
5015
  }
5013
5016
  }
5014
- if (cleaned > 0) {
5017
+ if (deleted.length > 0) {
5015
5018
  this.bumpMemoryStatusVersion();
5016
5019
  }
5017
- return cleaned;
5020
+ return deleted;
5018
5021
  }
5019
5022
  async loadBuffer() {
5020
5023
  const bufferPath = path4.join(this.stateDir, "buffer.json");
@@ -5499,7 +5502,7 @@ ${rows.join("\n")}
5499
5502
  async cleanExpiredCommitments(decayDays) {
5500
5503
  const memories = await this.readAllMemories();
5501
5504
  const cutoff = Date.now() - decayDays * 24 * 60 * 60 * 1e3;
5502
- let cleaned = 0;
5505
+ const deleted = [];
5503
5506
  for (const m of memories) {
5504
5507
  if (m.frontmatter.category !== "commitment") continue;
5505
5508
  const isResolved = m.frontmatter.tags.some(
@@ -5510,16 +5513,16 @@ ${rows.join("\n")}
5510
5513
  if (updatedAt < cutoff) {
5511
5514
  try {
5512
5515
  await unlink(m.path);
5513
- cleaned++;
5516
+ deleted.push(m);
5514
5517
  log.debug(`cleaned expired commitment ${m.frontmatter.id}`);
5515
5518
  } catch {
5516
5519
  }
5517
5520
  }
5518
5521
  }
5519
- if (cleaned > 0) {
5522
+ if (deleted.length > 0) {
5520
5523
  this.bumpMemoryStatusVersion();
5521
5524
  }
5522
- return cleaned;
5525
+ return deleted;
5523
5526
  }
5524
5527
  // ---------------------------------------------------------------------------
5525
5528
  // Access Tracking (Phase 1A)
@@ -8378,6 +8381,252 @@ function classifyMemoryKind(content, tags, category) {
8378
8381
  return "episode";
8379
8382
  }
8380
8383
 
8384
+ // src/temporal-index.ts
8385
+ import * as fs from "fs";
8386
+ import * as path14 from "path";
8387
+ var INDEX_VERSION = 1;
8388
+ var TEMPORAL_INDEX_FILE = "index_time.json";
8389
+ var TAG_INDEX_FILE = "index_tags.json";
8390
+ function stateDir(memoryDir) {
8391
+ return path14.join(memoryDir, "state");
8392
+ }
8393
+ function temporalIndexPath(memoryDir) {
8394
+ return path14.join(stateDir(memoryDir), TEMPORAL_INDEX_FILE);
8395
+ }
8396
+ function tagIndexPath(memoryDir) {
8397
+ return path14.join(stateDir(memoryDir), TAG_INDEX_FILE);
8398
+ }
8399
+ function ensureStateDir(memoryDir) {
8400
+ const dir = stateDir(memoryDir);
8401
+ if (!fs.existsSync(dir)) {
8402
+ fs.mkdirSync(dir, { recursive: true });
8403
+ }
8404
+ }
8405
+ function readJsonSafe(filePath, fallback) {
8406
+ try {
8407
+ const raw = fs.readFileSync(filePath, "utf8");
8408
+ return JSON.parse(raw);
8409
+ } catch {
8410
+ return fallback;
8411
+ }
8412
+ }
8413
+ function writeJsonSafe(filePath, data) {
8414
+ try {
8415
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
8416
+ } catch {
8417
+ }
8418
+ }
8419
+ function writeJsonAtomic(filePath, data) {
8420
+ const tmp = `${filePath}.tmp`;
8421
+ try {
8422
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
8423
+ fs.renameSync(tmp, filePath);
8424
+ } catch {
8425
+ writeJsonSafe(filePath, data);
8426
+ try {
8427
+ fs.unlinkSync(tmp);
8428
+ } catch {
8429
+ }
8430
+ }
8431
+ }
8432
+ function isoDateFromTimestamp(isoString) {
8433
+ if (typeof isoString !== "string" || isoString.length < 10) {
8434
+ console.warn(`[engram] temporal-index: malformed timestamp "${isoString}", falling back to today`);
8435
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8436
+ }
8437
+ return isoString.slice(0, 10);
8438
+ }
8439
+ function addPathToSet(record, key, p) {
8440
+ if (!record[key]) {
8441
+ record[key] = [];
8442
+ }
8443
+ if (!record[key].includes(p)) {
8444
+ record[key].push(p);
8445
+ }
8446
+ }
8447
+ function removePathFromSet(record, key, p) {
8448
+ if (!record[key]) return;
8449
+ record[key] = record[key].filter((x) => x !== p);
8450
+ if (record[key].length === 0) {
8451
+ delete record[key];
8452
+ }
8453
+ }
8454
+ function indexMemory(memoryDir, memoryPath, createdAt, tags) {
8455
+ try {
8456
+ ensureStateDir(memoryDir);
8457
+ const tPath = temporalIndexPath(memoryDir);
8458
+ const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
8459
+ const dateKey = isoDateFromTimestamp(createdAt);
8460
+ addPathToSet(tIndex.dates, dateKey, memoryPath);
8461
+ writeJsonAtomic(tPath, tIndex);
8462
+ const gPath = tagIndexPath(memoryDir);
8463
+ const gIndex = readJsonSafe(gPath, { version: INDEX_VERSION, tags: {} });
8464
+ for (const tag of tags) {
8465
+ if (tag && typeof tag === "string") {
8466
+ addPathToSet(gIndex.tags, tag.toLowerCase(), memoryPath);
8467
+ }
8468
+ }
8469
+ writeJsonAtomic(gPath, gIndex);
8470
+ } catch {
8471
+ }
8472
+ }
8473
+ function deindexMemory(memoryDir, memoryPath, createdAt, tags) {
8474
+ try {
8475
+ ensureStateDir(memoryDir);
8476
+ const tPath = temporalIndexPath(memoryDir);
8477
+ const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
8478
+ const dateKey = isoDateFromTimestamp(createdAt);
8479
+ removePathFromSet(tIndex.dates, dateKey, memoryPath);
8480
+ writeJsonAtomic(tPath, tIndex);
8481
+ const gPath = tagIndexPath(memoryDir);
8482
+ const gIndex = readJsonSafe(gPath, { version: INDEX_VERSION, tags: {} });
8483
+ for (const tag of tags) {
8484
+ if (tag && typeof tag === "string") {
8485
+ removePathFromSet(gIndex.tags, tag.toLowerCase(), memoryPath);
8486
+ }
8487
+ }
8488
+ writeJsonAtomic(gPath, gIndex);
8489
+ } catch {
8490
+ }
8491
+ }
8492
+ function clearIndexes(memoryDir) {
8493
+ try {
8494
+ ensureStateDir(memoryDir);
8495
+ writeJsonAtomic(temporalIndexPath(memoryDir), { version: INDEX_VERSION, dates: {} });
8496
+ writeJsonAtomic(tagIndexPath(memoryDir), { version: INDEX_VERSION, tags: {} });
8497
+ } catch {
8498
+ }
8499
+ }
8500
+ function indexesExist(memoryDir) {
8501
+ try {
8502
+ return fs.existsSync(temporalIndexPath(memoryDir)) && fs.existsSync(tagIndexPath(memoryDir));
8503
+ } catch {
8504
+ return false;
8505
+ }
8506
+ }
8507
+ function indexMemoriesBatch(memoryDir, entries) {
8508
+ if (entries.length === 0) return;
8509
+ try {
8510
+ ensureStateDir(memoryDir);
8511
+ const tPath = temporalIndexPath(memoryDir);
8512
+ const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
8513
+ const gPath = tagIndexPath(memoryDir);
8514
+ const gIndex = readJsonSafe(gPath, { version: INDEX_VERSION, tags: {} });
8515
+ for (const entry of entries) {
8516
+ const dateKey = isoDateFromTimestamp(entry.createdAt);
8517
+ addPathToSet(tIndex.dates, dateKey, entry.path);
8518
+ for (const tag of entry.tags) {
8519
+ if (tag && typeof tag === "string") {
8520
+ addPathToSet(gIndex.tags, tag.toLowerCase(), entry.path);
8521
+ }
8522
+ }
8523
+ }
8524
+ writeJsonAtomic(tPath, tIndex);
8525
+ writeJsonAtomic(gPath, gIndex);
8526
+ } catch {
8527
+ }
8528
+ }
8529
+ async function queryByDateRangeAsync(memoryDir, fromDate, toDate) {
8530
+ try {
8531
+ const tPath = temporalIndexPath(memoryDir);
8532
+ let raw;
8533
+ try {
8534
+ raw = await fs.promises.readFile(tPath, "utf8");
8535
+ } catch {
8536
+ return null;
8537
+ }
8538
+ let tIndex;
8539
+ try {
8540
+ tIndex = JSON.parse(raw);
8541
+ } catch {
8542
+ tIndex = { version: INDEX_VERSION, dates: {} };
8543
+ }
8544
+ const end = toDate ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8545
+ const results = /* @__PURE__ */ new Set();
8546
+ for (const [date, paths] of Object.entries(tIndex.dates)) {
8547
+ if (date >= fromDate && date <= end) {
8548
+ for (const p of paths) {
8549
+ results.add(p);
8550
+ }
8551
+ }
8552
+ }
8553
+ return results;
8554
+ } catch {
8555
+ return null;
8556
+ }
8557
+ }
8558
+ async function queryByTagsAsync(memoryDir, tags) {
8559
+ if (tags.length === 0) return null;
8560
+ try {
8561
+ const gPath = tagIndexPath(memoryDir);
8562
+ let raw;
8563
+ try {
8564
+ raw = await fs.promises.readFile(gPath, "utf8");
8565
+ } catch {
8566
+ return null;
8567
+ }
8568
+ let gIndex;
8569
+ try {
8570
+ gIndex = JSON.parse(raw);
8571
+ } catch {
8572
+ gIndex = { version: INDEX_VERSION, tags: {} };
8573
+ }
8574
+ const results = /* @__PURE__ */ new Set();
8575
+ for (const tag of tags) {
8576
+ const key = tag.toLowerCase();
8577
+ const paths = gIndex.tags[key] ?? [];
8578
+ for (const p of paths) {
8579
+ results.add(p);
8580
+ }
8581
+ }
8582
+ return results.size > 0 ? results : null;
8583
+ } catch {
8584
+ return null;
8585
+ }
8586
+ }
8587
+ function extractTagsFromPrompt(prompt) {
8588
+ const found = /* @__PURE__ */ new Set();
8589
+ const hashMatches = prompt.matchAll(/#([a-zA-Z][\w-]{1,30})/g);
8590
+ for (const m of hashMatches) {
8591
+ found.add(m[1].toLowerCase());
8592
+ }
8593
+ return Array.from(found);
8594
+ }
8595
+ function isTemporalQuery(prompt) {
8596
+ return /\b(today|yesterday|this week|last week|this month|last month|recent(?:ly)?|lately|just now|earlier today|this morning|last night|\d+ days? ago|\d+ hours? ago)\b/i.test(
8597
+ prompt
8598
+ );
8599
+ }
8600
+ function recencyWindowFromPrompt(prompt, nowMs = Date.now()) {
8601
+ const p = prompt.toLowerCase();
8602
+ let daysBack = 7;
8603
+ if (/\btoday\b/.test(p) || /\bthis morning\b/.test(p) || /\bjust now\b/.test(p) || /\bearlier today\b/.test(p)) {
8604
+ daysBack = 0;
8605
+ } else if (/\byesterday\b/.test(p) || /\blast night\b/.test(p)) {
8606
+ daysBack = 1;
8607
+ } else if (/\bthis week\b/.test(p)) {
8608
+ daysBack = 7;
8609
+ } else if (/\blast week\b/.test(p)) {
8610
+ daysBack = 14;
8611
+ } else if (/\bthis month\b/.test(p)) {
8612
+ daysBack = 31;
8613
+ } else if (/\blast month\b/.test(p)) {
8614
+ daysBack = 62;
8615
+ } else {
8616
+ const numMatch = p.match(/(\d{1,5})\s*days?\s*ago/);
8617
+ if (numMatch) {
8618
+ daysBack = Math.min(365, parseInt(numMatch[1], 10));
8619
+ } else {
8620
+ const hrMatch = p.match(/(\d{1,5})\s*hours?\s*ago/);
8621
+ if (hrMatch) {
8622
+ daysBack = Math.max(1, Math.ceil(parseInt(hrMatch[1], 10) / 24));
8623
+ }
8624
+ }
8625
+ }
8626
+ const from = new Date(nowMs - daysBack * 24 * 60 * 60 * 1e3);
8627
+ return from.toISOString().slice(0, 10);
8628
+ }
8629
+
8381
8630
  // src/conversation-index/chunker.ts
8382
8631
  function chunkTranscriptEntries(sessionKey, entries, opts) {
8383
8632
  const maxChars = Math.max(500, opts.maxChars);
@@ -8412,7 +8661,7 @@ function chunkTranscriptEntries(sessionKey, entries, opts) {
8412
8661
 
8413
8662
  // src/conversation-index/indexer.ts
8414
8663
  import { mkdir as mkdir11, writeFile as writeFile11 } from "fs/promises";
8415
- import path14 from "path";
8664
+ import path15 from "path";
8416
8665
  function sanitizeSessionKey(sessionKey) {
8417
8666
  const raw = typeof sessionKey === "string" && sessionKey.trim().length > 0 ? sessionKey : "unknown-session";
8418
8667
  return raw.toLowerCase().replace(/[^a-z0-9._-]+/g, "_").slice(0, 200);
@@ -8422,9 +8671,9 @@ async function writeConversationChunks(rootDir, chunks) {
8422
8671
  for (const c of chunks) {
8423
8672
  const safe = sanitizeSessionKey(c.sessionKey);
8424
8673
  const date = c.startTs.slice(0, 10);
8425
- const dir = path14.join(rootDir, safe, date);
8674
+ const dir = path15.join(rootDir, safe, date);
8426
8675
  await mkdir11(dir, { recursive: true });
8427
- const fp = path14.join(dir, `${c.id}.md`);
8676
+ const fp = path15.join(dir, `${c.id}.md`);
8428
8677
  const content = `---
8429
8678
  kind: conversation_chunk
8430
8679
  sessionKey: ${c.sessionKey}
@@ -8441,7 +8690,7 @@ endTs: ${c.endTs}
8441
8690
 
8442
8691
  // src/conversation-index/cleanup.ts
8443
8692
  import { readdir as readdir7, rm } from "fs/promises";
8444
- import path15 from "path";
8693
+ import path16 from "path";
8445
8694
  async function cleanupConversationChunks(rootDir, retentionDays) {
8446
8695
  if (!Number.isFinite(retentionDays) || retentionDays <= 0) return;
8447
8696
  const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
@@ -8449,7 +8698,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
8449
8698
  const sessions = await readdir7(rootDir, { withFileTypes: true });
8450
8699
  for (const s of sessions) {
8451
8700
  if (!s.isDirectory()) continue;
8452
- const sessionDir = path15.join(rootDir, s.name);
8701
+ const sessionDir = path16.join(rootDir, s.name);
8453
8702
  const dayDirs = await readdir7(sessionDir, { withFileTypes: true });
8454
8703
  for (const d of dayDirs) {
8455
8704
  if (!d.isDirectory()) continue;
@@ -8457,7 +8706,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
8457
8706
  const dayMs = (/* @__PURE__ */ new Date(d.name + "T00:00:00.000Z")).getTime();
8458
8707
  if (!Number.isFinite(dayMs)) continue;
8459
8708
  if (dayMs < cutoffMs) {
8460
- await rm(path15.join(sessionDir, d.name), { recursive: true, force: true });
8709
+ await rm(path16.join(sessionDir, d.name), { recursive: true, force: true });
8461
8710
  }
8462
8711
  }
8463
8712
  try {
@@ -8474,7 +8723,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
8474
8723
  }
8475
8724
 
8476
8725
  // src/namespaces/storage.ts
8477
- import path16 from "path";
8726
+ import path17 from "path";
8478
8727
  import { access } from "fs/promises";
8479
8728
  async function exists(p) {
8480
8729
  try {
@@ -8496,7 +8745,7 @@ var NamespaceStorageRouter = class {
8496
8745
  this.defaultNsRootResolved = this.config.memoryDir;
8497
8746
  return this.defaultNsRootResolved;
8498
8747
  }
8499
- const nsDir = path16.join(this.config.memoryDir, "namespaces", this.config.defaultNamespace);
8748
+ const nsDir = path17.join(this.config.memoryDir, "namespaces", this.config.defaultNamespace);
8500
8749
  this.defaultNsRootResolved = await exists(nsDir) ? nsDir : this.config.memoryDir;
8501
8750
  return this.defaultNsRootResolved;
8502
8751
  }
@@ -8505,7 +8754,7 @@ var NamespaceStorageRouter = class {
8505
8754
  if (namespace === this.config.defaultNamespace) {
8506
8755
  return this.defaultNsRootResolved ?? this.config.memoryDir;
8507
8756
  }
8508
- return path16.join(this.config.memoryDir, "namespaces", namespace);
8757
+ return path17.join(this.config.memoryDir, "namespaces", namespace);
8509
8758
  }
8510
8759
  async storageFor(namespace) {
8511
8760
  const ns = namespace || this.config.defaultNamespace;
@@ -8582,7 +8831,7 @@ function recallNamespacesForPrincipal(principal, config) {
8582
8831
 
8583
8832
  // src/shared-context/manager.ts
8584
8833
  import { mkdir as mkdir12, readFile as readFile12, readdir as readdir8, appendFile as appendFile3, writeFile as writeFile12, stat as stat2 } from "fs/promises";
8585
- import path17 from "path";
8834
+ import path18 from "path";
8586
8835
  import os3 from "os";
8587
8836
  import { z as z3 } from "zod";
8588
8837
  var SharedFeedbackEntrySchema = z3.object({
@@ -8604,15 +8853,15 @@ function ymd(d) {
8604
8853
  var SharedContextManager = class {
8605
8854
  constructor(config) {
8606
8855
  this.config = config;
8607
- const base = typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0 ? config.sharedContextDir : path17.join(os3.homedir(), ".openclaw", "workspace", "shared-context");
8856
+ const base = typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0 ? config.sharedContextDir : path18.join(os3.homedir(), ".openclaw", "workspace", "shared-context");
8608
8857
  this.dir = base;
8609
- this.prioritiesPath = path17.join(base, "priorities.md");
8610
- this.prioritiesInboxPath = path17.join(base, "priorities.inbox.md");
8611
- this.outputsDir = path17.join(base, "agent-outputs");
8612
- this.roundtableDir = path17.join(base, "roundtable");
8613
- this.feedbackDir = path17.join(base, "feedback");
8614
- this.feedbackInboxPath = path17.join(this.feedbackDir, "inbox.jsonl");
8615
- this.crossSignalsDir = path17.join(base, "cross-signals");
8858
+ this.prioritiesPath = path18.join(base, "priorities.md");
8859
+ this.prioritiesInboxPath = path18.join(base, "priorities.inbox.md");
8860
+ this.outputsDir = path18.join(base, "agent-outputs");
8861
+ this.roundtableDir = path18.join(base, "roundtable");
8862
+ this.feedbackDir = path18.join(base, "feedback");
8863
+ this.feedbackInboxPath = path18.join(this.feedbackDir, "inbox.jsonl");
8864
+ this.crossSignalsDir = path18.join(base, "cross-signals");
8616
8865
  }
8617
8866
  dir;
8618
8867
  prioritiesPath;
@@ -8628,10 +8877,10 @@ var SharedContextManager = class {
8628
8877
  await mkdir12(this.roundtableDir, { recursive: true });
8629
8878
  await mkdir12(this.feedbackDir, { recursive: true });
8630
8879
  await mkdir12(this.crossSignalsDir, { recursive: true });
8631
- await mkdir12(path17.join(this.dir, "staging"), { recursive: true });
8632
- await mkdir12(path17.join(this.dir, "kpis"), { recursive: true });
8633
- await mkdir12(path17.join(this.dir, "calendar"), { recursive: true });
8634
- await mkdir12(path17.join(this.dir, "content-calendar"), { recursive: true });
8880
+ await mkdir12(path18.join(this.dir, "staging"), { recursive: true });
8881
+ await mkdir12(path18.join(this.dir, "kpis"), { recursive: true });
8882
+ await mkdir12(path18.join(this.dir, "calendar"), { recursive: true });
8883
+ await mkdir12(path18.join(this.dir, "content-calendar"), { recursive: true });
8635
8884
  await this.ensureFile(
8636
8885
  this.prioritiesPath,
8637
8886
  [
@@ -8675,7 +8924,7 @@ var SharedContextManager = class {
8675
8924
  async readLatestRoundtable() {
8676
8925
  try {
8677
8926
  const files = (await readdir8(this.roundtableDir)).filter((f) => f.endsWith(".md")).sort().reverse();
8678
- const fp = files[0] ? path17.join(this.roundtableDir, files[0]) : null;
8927
+ const fp = files[0] ? path18.join(this.roundtableDir, files[0]) : null;
8679
8928
  if (!fp) return "";
8680
8929
  return await readFile12(fp, "utf-8");
8681
8930
  } catch {
@@ -8687,9 +8936,9 @@ var SharedContextManager = class {
8687
8936
  const date = ymd(createdAt);
8688
8937
  const time = createdAt.toISOString().slice(11, 19).replace(/:/g, "");
8689
8938
  const slug = safeSlug(opts.title);
8690
- const dir = path17.join(this.outputsDir, opts.agentId, date);
8939
+ const dir = path18.join(this.outputsDir, opts.agentId, date);
8691
8940
  await mkdir12(dir, { recursive: true });
8692
- const fp = path17.join(dir, `${time}-${slug}.md`);
8941
+ const fp = path18.join(dir, `${time}-${slug}.md`);
8693
8942
  const body = `---
8694
8943
  kind: agent_output
8695
8944
  agent: ${opts.agentId}
@@ -8724,11 +8973,11 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
8724
8973
  const agents = await readdir8(this.outputsDir, { withFileTypes: true });
8725
8974
  for (const a of agents) {
8726
8975
  if (!a.isDirectory()) continue;
8727
- const dayDir = path17.join(this.outputsDir, a.name, date);
8976
+ const dayDir = path18.join(this.outputsDir, a.name, date);
8728
8977
  try {
8729
8978
  const files = (await readdir8(dayDir)).filter((f) => f.endsWith(".md")).sort();
8730
8979
  for (const f of files) {
8731
- const p = path17.join(dayDir, f);
8980
+ const p = path18.join(dayDir, f);
8732
8981
  const raw = await readFile12(p, "utf-8");
8733
8982
  const title = (raw.match(/^title:\s*(.+)$/m)?.[1] ?? f).trim();
8734
8983
  outputs.push({ path: p, title });
@@ -8768,7 +9017,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
8768
9017
  ];
8769
9018
  const out = md.join("\n");
8770
9019
  const trimmed = out.length > maxChars ? out.slice(0, maxChars) + "\n\n...(trimmed)\n" : out;
8771
- const fp = path17.join(this.roundtableDir, `${date}.md`);
9020
+ const fp = path18.join(this.roundtableDir, `${date}.md`);
8772
9021
  await writeFile12(fp, trimmed, "utf-8");
8773
9022
  log.info(`shared-context curated daily roundtable: ${fp}`);
8774
9023
  return fp;
@@ -8777,7 +9026,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
8777
9026
 
8778
9027
  // src/compounding/engine.ts
8779
9028
  import { mkdir as mkdir13, readFile as readFile13, writeFile as writeFile13 } from "fs/promises";
8780
- import path18 from "path";
9029
+ import path19 from "path";
8781
9030
  import os4 from "os";
8782
9031
  function isoWeekId(d) {
8783
9032
  const dt = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
@@ -8792,28 +9041,28 @@ function sharedContextDir(config) {
8792
9041
  if (typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0) {
8793
9042
  return config.sharedContextDir;
8794
9043
  }
8795
- return path18.join(os4.homedir(), ".openclaw", "workspace", "shared-context");
9044
+ return path19.join(os4.homedir(), ".openclaw", "workspace", "shared-context");
8796
9045
  }
8797
9046
  var CompoundingEngine = class {
8798
9047
  constructor(config) {
8799
9048
  this.config = config;
8800
- this.weeklyDir = path18.join(config.memoryDir, "compounding", "weekly");
8801
- this.mistakesPath = path18.join(config.memoryDir, "compounding", "mistakes.json");
8802
- this.feedbackInboxPath = path18.join(sharedContextDir(config), "feedback", "inbox.jsonl");
9049
+ this.weeklyDir = path19.join(config.memoryDir, "compounding", "weekly");
9050
+ this.mistakesPath = path19.join(config.memoryDir, "compounding", "mistakes.json");
9051
+ this.feedbackInboxPath = path19.join(sharedContextDir(config), "feedback", "inbox.jsonl");
8803
9052
  }
8804
9053
  weeklyDir;
8805
9054
  mistakesPath;
8806
9055
  feedbackInboxPath;
8807
9056
  async ensureDirs() {
8808
9057
  await mkdir13(this.weeklyDir, { recursive: true });
8809
- await mkdir13(path18.dirname(this.mistakesPath), { recursive: true });
9058
+ await mkdir13(path19.dirname(this.mistakesPath), { recursive: true });
8810
9059
  }
8811
9060
  async synthesizeWeekly(opts) {
8812
9061
  await this.ensureDirs();
8813
9062
  const weekId = opts?.weekId ?? isoWeekId(/* @__PURE__ */ new Date());
8814
9063
  const entries = await this.readFeedbackEntriesForWeek(weekId);
8815
9064
  const mistakes = this.buildMistakes(entries);
8816
- const reportPath = path18.join(this.weeklyDir, `${weekId}.md`);
9065
+ const reportPath = path19.join(this.weeklyDir, `${weekId}.md`);
8817
9066
  const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns);
8818
9067
  await writeFile13(reportPath, md, "utf-8");
8819
9068
  await writeFile13(this.mistakesPath, JSON.stringify(mistakes, null, 2) + "\n", "utf-8");
@@ -9057,7 +9306,7 @@ var Orchestrator = class _Orchestrator {
9057
9306
  this.compounding = config.compoundingEnabled ? new CompoundingEngine(config) : void 0;
9058
9307
  this.buffer = new SmartBuffer(config, this.storage);
9059
9308
  this.transcript = new TranscriptManager(config);
9060
- this.conversationIndexDir = path19.join(config.memoryDir, "conversation-index", "chunks");
9309
+ this.conversationIndexDir = path20.join(config.memoryDir, "conversation-index", "chunks");
9061
9310
  this.modelRegistry = new ModelRegistry(config.memoryDir);
9062
9311
  this.relevance = new RelevanceStore(config.memoryDir);
9063
9312
  this.negatives = new NegativeExampleStore(config.memoryDir);
@@ -9067,7 +9316,7 @@ var Orchestrator = class _Orchestrator {
9067
9316
  this.localLlm = new LocalLlmClient(config, this.modelRegistry);
9068
9317
  this.extraction = new ExtractionEngine(config, this.localLlm, config.gatewayConfig, this.modelRegistry);
9069
9318
  this.threading = new ThreadingManager(
9070
- path19.join(config.memoryDir, "threads"),
9319
+ path20.join(config.memoryDir, "threads"),
9071
9320
  config.threadingGapMinutes
9072
9321
  );
9073
9322
  this.initPromise = new Promise((resolve) => {
@@ -9169,8 +9418,8 @@ var Orchestrator = class _Orchestrator {
9169
9418
  await this.negatives.load();
9170
9419
  await this.lastRecall.load();
9171
9420
  if (this.config.factDeduplicationEnabled) {
9172
- const stateDir = path19.join(this.config.memoryDir, "state");
9173
- this.contentHashIndex = new ContentHashIndex(stateDir);
9421
+ const stateDir2 = path20.join(this.config.memoryDir, "state");
9422
+ this.contentHashIndex = new ContentHashIndex(stateDir2);
9174
9423
  await this.contentHashIndex.load();
9175
9424
  log.info(`content-hash dedup: loaded ${this.contentHashIndex.size} hashes`);
9176
9425
  }
@@ -9207,7 +9456,7 @@ var Orchestrator = class _Orchestrator {
9207
9456
  if (available) {
9208
9457
  log.info(`Conversation index QMD: available ${this.conversationQmd.debugStatus()}`);
9209
9458
  const collectionState = await this.conversationQmd.ensureCollection(
9210
- path19.join(this.config.memoryDir, "conversation-index")
9459
+ path20.join(this.config.memoryDir, "conversation-index")
9211
9460
  );
9212
9461
  if (collectionState === "missing") {
9213
9462
  this.config.conversationIndexEnabled = false;
@@ -9243,12 +9492,12 @@ var Orchestrator = class _Orchestrator {
9243
9492
  this.lastFileHygieneRunAtMs = now;
9244
9493
  if (hygiene.rotateEnabled) {
9245
9494
  for (const rel of hygiene.rotatePaths) {
9246
- const abs = path19.isAbsolute(rel) ? rel : path19.join(this.config.workspaceDir, rel);
9495
+ const abs = path20.isAbsolute(rel) ? rel : path20.join(this.config.workspaceDir, rel);
9247
9496
  try {
9248
9497
  const raw = await readFile14(abs, "utf-8");
9249
9498
  if (raw.length > hygiene.rotateMaxBytes) {
9250
- const archiveDir = path19.join(this.config.workspaceDir, hygiene.archiveDir);
9251
- const base = path19.basename(abs);
9499
+ const archiveDir = path20.join(this.config.workspaceDir, hygiene.archiveDir);
9500
+ const base = path20.basename(abs);
9252
9501
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
9253
9502
  const { newContent } = await rotateMarkdownFileToArchive({
9254
9503
  filePath: abs,
@@ -9273,8 +9522,8 @@ var Orchestrator = class _Orchestrator {
9273
9522
  log.warn(w.message);
9274
9523
  }
9275
9524
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
9276
- const fp = path19.join(this.config.memoryDir, hygiene.warningsLogPath);
9277
- await mkdir14(path19.dirname(fp), { recursive: true });
9525
+ const fp = path20.join(this.config.memoryDir, hygiene.warningsLogPath);
9526
+ await mkdir14(path20.dirname(fp), { recursive: true });
9278
9527
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
9279
9528
  const block = `
9280
9529
 
@@ -9803,21 +10052,26 @@ ${boxLines.join("\n")}`);
9803
10052
  const activeMemories = memories.filter(
9804
10053
  (m) => !m.frontmatter.status || m.frontmatter.status === "active"
9805
10054
  );
9806
- const recent = activeMemories.sort(
10055
+ const recentSorted = activeMemories.sort(
9807
10056
  (a, b) => new Date(b.frontmatter.updated).getTime() - new Date(a.frontmatter.updated).getTime()
9808
- ).slice(0, recallResultLimit);
9809
- const memoryIds = recent.map((m) => m.frontmatter.id);
10057
+ );
10058
+ const preloadedMap = new Map(
10059
+ activeMemories.filter((m) => m.path).map((m) => [m.path, m])
10060
+ );
10061
+ const recentAsResults = recentSorted.map((m, i) => ({
10062
+ docid: m.frontmatter.id,
10063
+ path: m.path,
10064
+ snippet: m.content,
10065
+ score: 1 - i / Math.max(recentSorted.length, 1)
10066
+ }));
10067
+ const recent = (await this.boostSearchResults(recentAsResults, recallNamespaces, prompt, preloadedMap)).sort((a, b) => b.score - a.score).slice(0, recallResultLimit);
10068
+ const memoryIds = recent.map((r) => r.docid).filter(Boolean);
9810
10069
  this.trackMemoryAccess(memoryIds);
9811
10070
  if (sessionKey) {
9812
10071
  const unique = Array.from(new Set(memoryIds)).slice(0, 40);
9813
10072
  this.lastRecall.record({ sessionKey, query: prompt, memoryIds: unique }).catch((err) => log.debug(`last recall record failed: ${err}`));
9814
10073
  }
9815
- const lines = recent.map(
9816
- (m) => `- [${m.frontmatter.category}] ${m.content}`
9817
- );
9818
- sections.push(`## Recent Memories
9819
-
9820
- ${lines.join("\n")}`);
10074
+ sections.push(this.formatQmdResults("Recent Memories", recent));
9821
10075
  }
9822
10076
  }
9823
10077
  if (isDisagreementPrompt(prompt)) {
@@ -10234,7 +10488,8 @@ _Context: ${topQuestion.context}_`);
10234
10488
  this.contentHashIndex.add(fact.content);
10235
10489
  }
10236
10490
  for (const chunk of chunkResult.chunks) {
10237
- await this.indexPersistedMemory(storage, `${parentId}-chunk-${chunk.index}`);
10491
+ const chunkId = `${parentId}-chunk-${chunk.index}`;
10492
+ await this.indexPersistedMemory(storage, chunkId);
10238
10493
  }
10239
10494
  if (this.config.verbatimArtifactsEnabled && this.config.verbatimArtifactCategories.includes(fact.category) && fact.confidence >= this.config.verbatimArtifactsMinConfidence) {
10240
10495
  await storage.writeArtifact(fact.content, {
@@ -10262,6 +10517,14 @@ _Context: ${topQuestion.context}_`);
10262
10517
  strength: contradiction.confidence,
10263
10518
  reason: contradiction.reason
10264
10519
  });
10520
+ if (this.config.queryAwareIndexingEnabled && contradiction.supersededPath) {
10521
+ deindexMemory(
10522
+ this.config.memoryDir,
10523
+ contradiction.supersededPath,
10524
+ contradiction.supersededCreated,
10525
+ contradiction.supersededTags
10526
+ );
10527
+ }
10265
10528
  }
10266
10529
  }
10267
10530
  if (this.config.memoryLinkingEnabled && this.qmd.isAvailable()) {
@@ -10366,6 +10629,9 @@ _Context: ${topQuestion.context}_`);
10366
10629
  log.info(
10367
10630
  `persisted: ${facts.length - dedupedCount} facts${dedupSuffix}, ${entities.length} entities, ${questions.length} questions, ${profileUpdates.length} profile updates`
10368
10631
  );
10632
+ this.updateTemporalTagIndexes(storage, persistedIds).catch(
10633
+ (err) => log.debug(`temporal-index update error (non-fatal): ${err}`)
10634
+ );
10369
10635
  return persistedIds;
10370
10636
  }
10371
10637
  async indexPersistedMemory(storage, memoryId) {
@@ -10375,6 +10641,52 @@ _Context: ${topQuestion.context}_`);
10375
10641
  if (!memory) return;
10376
10642
  await this.embeddingFallback.indexFile(memoryId, memory.content, memory.path);
10377
10643
  }
10644
+ /**
10645
+ * Batch-update temporal and tag indexes after extraction (v8.1).
10646
+ * Reads each persisted memory's path + frontmatter and adds them to
10647
+ * state/index_time.json and state/index_tags.json.
10648
+ * Fail-open: any error is logged but does not abort extraction.
10649
+ */
10650
+ async updateTemporalTagIndexes(storage, persistedIds) {
10651
+ if (!this.config.queryAwareIndexingEnabled) return;
10652
+ const needsFullRebuild = !indexesExist(this.config.memoryDir);
10653
+ if (!needsFullRebuild && persistedIds.length === 0) return;
10654
+ try {
10655
+ const allMemories = needsFullRebuild && this.config.namespacesEnabled ? await this.readAllMemoriesForNamespaces(
10656
+ Array.from(/* @__PURE__ */ new Set([
10657
+ this.config.defaultNamespace,
10658
+ this.config.sharedNamespace,
10659
+ ...this.config.namespacePolicies.map((p) => p.name)
10660
+ ]))
10661
+ ) : await storage.readAllMemories();
10662
+ const isActive = (m) => !m.frontmatter.status || m.frontmatter.status === "active";
10663
+ const pool = needsFullRebuild ? allMemories.filter(isActive) : (() => {
10664
+ const idSet = new Set(persistedIds);
10665
+ return allMemories.filter((m) => idSet.has(m.frontmatter.id));
10666
+ })();
10667
+ const entries = [];
10668
+ for (const mem of pool) {
10669
+ if (mem.path && mem.frontmatter?.created) {
10670
+ entries.push({
10671
+ path: mem.path,
10672
+ createdAt: mem.frontmatter.created,
10673
+ tags: mem.frontmatter.tags ?? []
10674
+ });
10675
+ }
10676
+ }
10677
+ if (needsFullRebuild) {
10678
+ clearIndexes(this.config.memoryDir);
10679
+ if (entries.length > 0) {
10680
+ indexMemoriesBatch(this.config.memoryDir, entries);
10681
+ }
10682
+ log.info(`temporal-index: bootstrapped from ${entries.length} active memories`);
10683
+ } else if (entries.length > 0) {
10684
+ indexMemoriesBatch(this.config.memoryDir, entries);
10685
+ }
10686
+ } catch (err) {
10687
+ log.debug(`temporal-index update failed (non-fatal): ${err}`);
10688
+ }
10689
+ }
10378
10690
  /** IDs of facts persisted in the last extraction */
10379
10691
  lastPersistedIds = [];
10380
10692
  async runConsolidation() {
@@ -10396,14 +10708,25 @@ _Context: ${topQuestion.context}_`);
10396
10708
  );
10397
10709
  const profile = await this.storage.readProfile();
10398
10710
  const result = await this.extraction.consolidate(recent, older, profile);
10711
+ const memoryLookup = this.config.queryAwareIndexingEnabled ? new Map(allMemories.map((m) => [m.frontmatter.id, m])) : null;
10399
10712
  for (const item of result.items) {
10400
10713
  switch (item.action) {
10401
- case "INVALIDATE":
10714
+ case "INVALIDATE": {
10715
+ const toInvalidate = this.config.queryAwareIndexingEnabled ? memoryLookup?.get(item.existingId) ?? null : null;
10402
10716
  if (await this.storage.invalidateMemory(item.existingId)) {
10403
10717
  invalidated += 1;
10404
10718
  await this.embeddingFallback.removeFromIndex(item.existingId);
10719
+ if (toInvalidate?.path && toInvalidate.frontmatter?.created) {
10720
+ deindexMemory(
10721
+ this.config.memoryDir,
10722
+ toInvalidate.path,
10723
+ toInvalidate.frontmatter.created,
10724
+ toInvalidate.frontmatter.tags ?? []
10725
+ );
10726
+ }
10405
10727
  }
10406
10728
  break;
10729
+ }
10407
10730
  case "UPDATE":
10408
10731
  if (item.updatedContent) {
10409
10732
  await this.storage.updateMemory(item.existingId, item.updatedContent, {
@@ -10419,10 +10742,19 @@ _Context: ${topQuestion.context}_`);
10419
10742
  lineage: [item.existingId, item.mergeWith]
10420
10743
  });
10421
10744
  await this.indexPersistedMemory(this.storage, item.existingId);
10745
+ const toMergeInvalidate = this.config.queryAwareIndexingEnabled ? memoryLookup?.get(item.mergeWith) ?? null : null;
10422
10746
  if (await this.storage.invalidateMemory(item.mergeWith)) {
10423
10747
  invalidated += 1;
10424
10748
  merged += 1;
10425
10749
  await this.embeddingFallback.removeFromIndex(item.mergeWith);
10750
+ if (toMergeInvalidate?.path && toMergeInvalidate.frontmatter?.created) {
10751
+ deindexMemory(
10752
+ this.config.memoryDir,
10753
+ toMergeInvalidate.path,
10754
+ toMergeInvalidate.frontmatter.created,
10755
+ toMergeInvalidate.frontmatter.tags ?? []
10756
+ );
10757
+ }
10426
10758
  }
10427
10759
  }
10428
10760
  break;
@@ -10477,13 +10809,23 @@ _Context: ${topQuestion.context}_`);
10477
10809
  log.debug(`entity summary pass failed: ${err}`);
10478
10810
  }
10479
10811
  }
10480
- const cleaned = await this.storage.cleanExpiredCommitments(this.config.commitmentDecayDays);
10481
- if (cleaned > 0) {
10482
- log.info(`cleaned ${cleaned} expired commitments`);
10812
+ const deletedCommitments = await this.storage.cleanExpiredCommitments(this.config.commitmentDecayDays);
10813
+ if (deletedCommitments.length > 0) {
10814
+ log.info(`cleaned ${deletedCommitments.length} expired commitments`);
10815
+ if (this.config.queryAwareIndexingEnabled) {
10816
+ for (const m of deletedCommitments) {
10817
+ deindexMemory(this.config.memoryDir, m.path, m.frontmatter.created, m.frontmatter.tags ?? []);
10818
+ }
10819
+ }
10483
10820
  }
10484
- const ttlCleaned = await this.storage.cleanExpiredTTL();
10485
- if (ttlCleaned > 0) {
10486
- log.info(`cleaned ${ttlCleaned} TTL-expired memories`);
10821
+ const deletedTTL = await this.storage.cleanExpiredTTL();
10822
+ if (deletedTTL.length > 0) {
10823
+ log.info(`cleaned ${deletedTTL.length} TTL-expired memories`);
10824
+ if (this.config.queryAwareIndexingEnabled) {
10825
+ for (const m of deletedTTL) {
10826
+ deindexMemory(this.config.memoryDir, m.path, m.frontmatter.created, m.frontmatter.tags ?? []);
10827
+ }
10828
+ }
10487
10829
  }
10488
10830
  if (this.config.factArchivalEnabled) {
10489
10831
  const archived = await this.runFactArchival(allMemories);
@@ -10544,6 +10886,14 @@ _Context: ${topQuestion.context}_`);
10544
10886
  this.contentHashIndex.remove(memory.content);
10545
10887
  }
10546
10888
  await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
10889
+ if (this.config.queryAwareIndexingEnabled && memory.path && memory.frontmatter?.created) {
10890
+ deindexMemory(
10891
+ this.config.memoryDir,
10892
+ memory.path,
10893
+ memory.frontmatter.created,
10894
+ memory.frontmatter.tags ?? []
10895
+ );
10896
+ }
10547
10897
  archivedCount++;
10548
10898
  }
10549
10899
  }
@@ -10671,7 +11021,7 @@ ${lines.join("\n\n")}`;
10671
11021
  if (hits.length === 0) return [];
10672
11022
  const results = [];
10673
11023
  for (const hit of hits) {
10674
- const fullPath = path19.isAbsolute(hit.path) ? hit.path : path19.join(this.config.memoryDir, hit.path);
11024
+ const fullPath = path20.isAbsolute(hit.path) ? hit.path : path20.join(this.config.memoryDir, hit.path);
10675
11025
  const memory = await this.storage.readMemoryByPath(fullPath);
10676
11026
  if (!memory) continue;
10677
11027
  results.push({
@@ -10751,18 +11101,48 @@ ${lines.join("\n\n")}`;
10751
11101
  * Apply recency, access count, and importance boosting to QMD search results.
10752
11102
  * Returns re-ranked results.
10753
11103
  */
10754
- async boostSearchResults(results, _recallNamespaces, prompt) {
11104
+ async boostSearchResults(results, _recallNamespaces, prompt, preloadedMemoryMap) {
10755
11105
  if (results.length === 0) return results;
10756
11106
  const now = Date.now();
10757
- const memoryByPath = /* @__PURE__ */ new Map();
10758
- await Promise.all(
10759
- results.map(async (r) => {
10760
- if (!r.path || memoryByPath.has(r.path)) return;
10761
- const mem = await this.storage.readMemoryByPath(r.path);
10762
- if (mem) memoryByPath.set(r.path, mem);
10763
- })
10764
- );
11107
+ const memoryByPath = preloadedMemoryMap ? new Map(preloadedMemoryMap) : /* @__PURE__ */ new Map();
11108
+ const resultPaths = new Set(results.map((r) => r.path).filter(Boolean));
11109
+ let temporalFromDate = null;
11110
+ let promptTags = [];
11111
+ if (this.config.queryAwareIndexingEnabled && prompt) {
11112
+ if (isTemporalQuery(prompt)) {
11113
+ temporalFromDate = recencyWindowFromPrompt(prompt, now);
11114
+ }
11115
+ promptTags = extractTagsFromPrompt(prompt);
11116
+ }
11117
+ const [, rawTemporal, rawTags] = await Promise.all([
11118
+ Promise.all(
11119
+ results.map(async (r) => {
11120
+ if (!r.path || memoryByPath.has(r.path)) return;
11121
+ const mem = await this.storage.readMemoryByPath(r.path);
11122
+ if (mem) memoryByPath.set(r.path, mem);
11123
+ })
11124
+ ),
11125
+ temporalFromDate !== null ? queryByDateRangeAsync(this.config.memoryDir, temporalFromDate) : Promise.resolve(null),
11126
+ promptTags.length > 0 ? queryByTagsAsync(this.config.memoryDir, promptTags) : Promise.resolve(null)
11127
+ ]);
10765
11128
  const queryIntent = this.config.intentRoutingEnabled && prompt ? inferIntentFromText(prompt) : null;
11129
+ let temporalCandidates = null;
11130
+ let tagCandidates = null;
11131
+ if (this.config.queryAwareIndexingEnabled && prompt) {
11132
+ const maxCandidates = this.config.queryAwareIndexingMaxCandidates;
11133
+ const capSet = (s) => {
11134
+ if (!s) return null;
11135
+ const scoped = new Set(Array.from(s).filter((p) => resultPaths.has(p)));
11136
+ if (maxCandidates === 0 || scoped.size <= maxCandidates) return scoped.size > 0 ? scoped : null;
11137
+ return new Set(Array.from(scoped).slice(0, maxCandidates));
11138
+ };
11139
+ if (temporalFromDate !== null) {
11140
+ temporalCandidates = capSet(rawTemporal);
11141
+ }
11142
+ if (promptTags.length > 0) {
11143
+ tagCandidates = capSet(rawTags);
11144
+ }
11145
+ }
10766
11146
  const boosted = results.map((r) => {
10767
11147
  const memory = memoryByPath.get(r.path);
10768
11148
  let score = r.score;
@@ -10809,6 +11189,14 @@ ${lines.join("\n\n")}`;
10809
11189
  });
10810
11190
  score += compatibility * this.config.intentRoutingBoost;
10811
11191
  }
11192
+ if (this.config.queryAwareIndexingEnabled && r.path) {
11193
+ if (temporalCandidates?.has(r.path)) {
11194
+ score += 0.08;
11195
+ }
11196
+ if (tagCandidates?.has(r.path)) {
11197
+ score += 0.06;
11198
+ }
11199
+ }
10812
11200
  }
10813
11201
  return { ...r, score };
10814
11202
  });
@@ -10877,7 +11265,10 @@ ${lines.join("\n\n")}`;
10877
11265
  return {
10878
11266
  supersededId: existingMemory.frontmatter.id,
10879
11267
  confidence: verification.confidence,
10880
- reason: verification.reasoning
11268
+ reason: verification.reasoning,
11269
+ supersededPath: existingMemory.path,
11270
+ supersededCreated: existingMemory.frontmatter.created,
11271
+ supersededTags: existingMemory.frontmatter.tags ?? []
10881
11272
  };
10882
11273
  }
10883
11274
  }
@@ -10942,7 +11333,7 @@ ${lines.join("\n\n")}`;
10942
11333
  };
10943
11334
 
10944
11335
  // src/tools.ts
10945
- import path20 from "path";
11336
+ import path21 from "path";
10946
11337
  import { Type } from "@sinclair/typebox";
10947
11338
  function toolResult(text) {
10948
11339
  return { content: [{ type: "text", text }], details: void 0 };
@@ -11217,6 +11608,12 @@ Best for:
11217
11608
  source: "explicit"
11218
11609
  }
11219
11610
  );
11611
+ if (orchestrator.config.queryAwareIndexingEnabled && indexesExist(orchestrator.config.memoryDir)) {
11612
+ const mem = await storage.getMemoryById(id).catch(() => null);
11613
+ if (mem?.path && mem.frontmatter?.created) {
11614
+ indexMemory(orchestrator.config.memoryDir, mem.path, mem.frontmatter.created, mem.frontmatter.tags ?? []);
11615
+ }
11616
+ }
11220
11617
  orchestrator.requestQmdMaintenanceForTool("memory_store");
11221
11618
  return toolResult(`Memory stored: ${id}${namespace ? ` (namespace: ${namespace})` : ""}
11222
11619
 
@@ -11274,6 +11671,12 @@ Content: ${content}`);
11274
11671
  supersedes: mem.frontmatter.supersedes,
11275
11672
  links: mem.frontmatter.links
11276
11673
  });
11674
+ if (orchestrator.config.queryAwareIndexingEnabled && indexesExist(orchestrator.config.memoryDir)) {
11675
+ const promoted = await dst.getMemoryById(newId).catch(() => null);
11676
+ if (promoted?.path && promoted.frontmatter?.created) {
11677
+ indexMemory(orchestrator.config.memoryDir, promoted.path, promoted.frontmatter.created, promoted.frontmatter.tags ?? []);
11678
+ }
11679
+ }
11277
11680
  return toolResult(`Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`);
11278
11681
  }
11279
11682
  },
@@ -11420,7 +11823,7 @@ Best for:
11420
11823
  - Reviewing identity development over time`,
11421
11824
  parameters: Type.Object({}),
11422
11825
  async execute() {
11423
- const workspaceDir = path20.join(process.env.HOME ?? "~", ".openclaw", "workspace");
11826
+ const workspaceDir = path21.join(process.env.HOME ?? "~", ".openclaw", "workspace");
11424
11827
  const identity = await orchestrator.storage.readIdentity(workspaceDir);
11425
11828
  if (!identity) {
11426
11829
  return toolResult("No identity file found. Identity reflections build automatically through conversations when identityEnabled is true.");
@@ -11669,11 +12072,11 @@ mistakes: ${res.mistakesCount} patterns`
11669
12072
  }
11670
12073
 
11671
12074
  // src/cli.ts
11672
- import path30 from "path";
12075
+ import path31 from "path";
11673
12076
  import { access as access2, readFile as readFile20 } from "fs/promises";
11674
12077
 
11675
12078
  // src/transfer/export-json.ts
11676
- import path22 from "path";
12079
+ import path23 from "path";
11677
12080
  import { mkdir as mkdir16, readFile as readFile16 } from "fs/promises";
11678
12081
 
11679
12082
  // src/transfer/constants.ts
@@ -11683,7 +12086,7 @@ var EXPORT_SCHEMA_VERSION = 1;
11683
12086
  // src/transfer/fs-utils.ts
11684
12087
  import { createHash as createHash5 } from "crypto";
11685
12088
  import { mkdir as mkdir15, readdir as readdir9, readFile as readFile15, stat as stat3, writeFile as writeFile15 } from "fs/promises";
11686
- import path21 from "path";
12089
+ import path22 from "path";
11687
12090
  async function sha256File(filePath) {
11688
12091
  const buf = await readFile15(filePath);
11689
12092
  const sha256 = createHash5("sha256").update(buf).digest("hex");
@@ -11695,7 +12098,7 @@ function sha256String(content) {
11695
12098
  return { sha256, bytes: buf.byteLength };
11696
12099
  }
11697
12100
  async function writeJsonFile(filePath, value) {
11698
- await mkdir15(path21.dirname(filePath), { recursive: true });
12101
+ await mkdir15(path22.dirname(filePath), { recursive: true });
11699
12102
  await writeFile15(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
11700
12103
  }
11701
12104
  async function readJsonFile(filePath) {
@@ -11707,7 +12110,7 @@ async function listFilesRecursive(rootDir) {
11707
12110
  async function walk(dir) {
11708
12111
  const entries = await readdir9(dir, { withFileTypes: true });
11709
12112
  for (const ent of entries) {
11710
- const fp = path21.join(dir, ent.name);
12113
+ const fp = path22.join(dir, ent.name);
11711
12114
  if (ent.isDirectory()) {
11712
12115
  await walk(fp);
11713
12116
  } else if (ent.isFile()) {
@@ -11727,11 +12130,11 @@ async function fileExists(filePath) {
11727
12130
  }
11728
12131
  }
11729
12132
  function toPosixRelPath(absPath, rootDir) {
11730
- const rel = path21.relative(rootDir, absPath);
11731
- return rel.split(path21.sep).join("/");
12133
+ const rel = path22.relative(rootDir, absPath);
12134
+ return rel.split(path22.sep).join("/");
11732
12135
  }
11733
12136
  function fromPosixRelPath(relPath) {
11734
- return relPath.split("/").join(path21.sep);
12137
+ return relPath.split("/").join(path22.sep);
11735
12138
  }
11736
12139
 
11737
12140
  // src/transfer/export-json.ts
@@ -11747,9 +12150,9 @@ function shouldExclude(relPosix, includeTranscripts) {
11747
12150
  }
11748
12151
  async function exportJsonBundle(opts) {
11749
12152
  const includeTranscripts = opts.includeTranscripts === true;
11750
- const outDirAbs = path22.resolve(opts.outDir);
12153
+ const outDirAbs = path23.resolve(opts.outDir);
11751
12154
  await mkdir16(outDirAbs, { recursive: true });
11752
- const memoryDirAbs = path22.resolve(opts.memoryDir);
12155
+ const memoryDirAbs = path23.resolve(opts.memoryDir);
11753
12156
  const filesAbs = await listFilesRecursive(memoryDirAbs);
11754
12157
  const records = [];
11755
12158
  const manifestFiles = [];
@@ -11762,7 +12165,7 @@ async function exportJsonBundle(opts) {
11762
12165
  manifestFiles.push({ path: relPosix, sha256, bytes });
11763
12166
  }
11764
12167
  if (opts.includeWorkspaceIdentity !== false && opts.workspaceDir) {
11765
- const identityPath = path22.join(opts.workspaceDir, "IDENTITY.md");
12168
+ const identityPath = path23.join(opts.workspaceDir, "IDENTITY.md");
11766
12169
  try {
11767
12170
  const content = await readFile16(identityPath, "utf-8");
11768
12171
  const relPath = "workspace/IDENTITY.md";
@@ -11781,12 +12184,12 @@ async function exportJsonBundle(opts) {
11781
12184
  files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
11782
12185
  };
11783
12186
  const bundle = { manifest, records };
11784
- await writeJsonFile(path22.join(outDirAbs, "manifest.json"), manifest);
11785
- await writeJsonFile(path22.join(outDirAbs, "bundle.json"), bundle);
12187
+ await writeJsonFile(path23.join(outDirAbs, "manifest.json"), manifest);
12188
+ await writeJsonFile(path23.join(outDirAbs, "bundle.json"), bundle);
11786
12189
  }
11787
12190
 
11788
12191
  // src/transfer/export-md.ts
11789
- import path23 from "path";
12192
+ import path24 from "path";
11790
12193
  import { mkdir as mkdir17, readFile as readFile17, writeFile as writeFile16 } from "fs/promises";
11791
12194
  function shouldExclude2(relPosix, includeTranscripts) {
11792
12195
  const parts = relPosix.split("/");
@@ -11795,16 +12198,16 @@ function shouldExclude2(relPosix, includeTranscripts) {
11795
12198
  }
11796
12199
  async function exportMarkdownBundle(opts) {
11797
12200
  const includeTranscripts = opts.includeTranscripts === true;
11798
- const outDirAbs = path23.resolve(opts.outDir);
12201
+ const outDirAbs = path24.resolve(opts.outDir);
11799
12202
  await mkdir17(outDirAbs, { recursive: true });
11800
- const memDirAbs = path23.resolve(opts.memoryDir);
12203
+ const memDirAbs = path24.resolve(opts.memoryDir);
11801
12204
  const filesAbs = await listFilesRecursive(memDirAbs);
11802
12205
  const manifestFiles = [];
11803
12206
  for (const abs of filesAbs) {
11804
12207
  const relPosix = toPosixRelPath(abs, memDirAbs);
11805
12208
  if (shouldExclude2(relPosix, includeTranscripts)) continue;
11806
- const dstAbs = path23.join(outDirAbs, ...relPosix.split("/"));
11807
- await mkdir17(path23.dirname(dstAbs), { recursive: true });
12209
+ const dstAbs = path24.join(outDirAbs, ...relPosix.split("/"));
12210
+ await mkdir17(path24.dirname(dstAbs), { recursive: true });
11808
12211
  const content = await readFile17(abs);
11809
12212
  await writeFile16(dstAbs, content);
11810
12213
  const { sha256, bytes } = await sha256File(abs);
@@ -11818,12 +12221,12 @@ async function exportMarkdownBundle(opts) {
11818
12221
  includesTranscripts: includeTranscripts,
11819
12222
  files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
11820
12223
  };
11821
- await writeJsonFile(path23.join(outDirAbs, "manifest.json"), manifest);
12224
+ await writeJsonFile(path24.join(outDirAbs, "manifest.json"), manifest);
11822
12225
  }
11823
12226
  async function looksLikeEngramMdExport(fromDir) {
11824
- const dirAbs = path23.resolve(fromDir);
12227
+ const dirAbs = path24.resolve(fromDir);
11825
12228
  try {
11826
- const raw = await readFile17(path23.join(dirAbs, "manifest.json"), "utf-8");
12229
+ const raw = await readFile17(path24.join(dirAbs, "manifest.json"), "utf-8");
11827
12230
  const parsed = JSON.parse(raw);
11828
12231
  return parsed.format === EXPORT_FORMAT && parsed.schemaVersion === EXPORT_SCHEMA_VERSION;
11829
12232
  } catch {
@@ -11832,16 +12235,16 @@ async function looksLikeEngramMdExport(fromDir) {
11832
12235
  }
11833
12236
 
11834
12237
  // src/transfer/backup.ts
11835
- import path24 from "path";
12238
+ import path25 from "path";
11836
12239
  import { mkdir as mkdir18, readdir as readdir10, rm as rm2 } from "fs/promises";
11837
12240
  function timestampDirName(now) {
11838
12241
  return now.toISOString().replace(/[:.]/g, "-");
11839
12242
  }
11840
12243
  async function backupMemoryDir(opts) {
11841
- const outDirAbs = path24.resolve(opts.outDir);
12244
+ const outDirAbs = path25.resolve(opts.outDir);
11842
12245
  await mkdir18(outDirAbs, { recursive: true });
11843
12246
  const ts = timestampDirName(/* @__PURE__ */ new Date());
11844
- const backupDir = path24.join(outDirAbs, ts);
12247
+ const backupDir = path25.join(outDirAbs, ts);
11845
12248
  await exportMarkdownBundle({
11846
12249
  memoryDir: opts.memoryDir,
11847
12250
  outDir: backupDir,
@@ -11866,13 +12269,13 @@ async function enforceRetention(outDirAbs, retentionDays) {
11866
12269
  const tsMs = iso ? Date.parse(iso) : NaN;
11867
12270
  if (!Number.isFinite(tsMs)) continue;
11868
12271
  if (tsMs < cutoffMs) {
11869
- await rm2(path24.join(outDirAbs, name), { recursive: true, force: true });
12272
+ await rm2(path25.join(outDirAbs, name), { recursive: true, force: true });
11870
12273
  }
11871
12274
  }
11872
12275
  }
11873
12276
 
11874
12277
  // src/transfer/export-sqlite.ts
11875
- import path25 from "path";
12278
+ import path26 from "path";
11876
12279
  import Database from "better-sqlite3";
11877
12280
  import { readFile as readFile18 } from "fs/promises";
11878
12281
 
@@ -11900,8 +12303,8 @@ function shouldExclude3(relPosix, includeTranscripts) {
11900
12303
  }
11901
12304
  async function exportSqlite(opts) {
11902
12305
  const includeTranscripts = opts.includeTranscripts === true;
11903
- const memDirAbs = path25.resolve(opts.memoryDir);
11904
- const outAbs = path25.resolve(opts.outFile);
12306
+ const memDirAbs = path26.resolve(opts.memoryDir);
12307
+ const outAbs = path26.resolve(opts.outFile);
11905
12308
  const filesAbs = await listFilesRecursive(memDirAbs);
11906
12309
  const db = new Database(outAbs);
11907
12310
  try {
@@ -11933,7 +12336,7 @@ async function exportSqlite(opts) {
11933
12336
  }
11934
12337
 
11935
12338
  // src/transfer/import-json.ts
11936
- import path26 from "path";
12339
+ import path27 from "path";
11937
12340
  import { mkdir as mkdir19, writeFile as writeFile17 } from "fs/promises";
11938
12341
 
11939
12342
  // src/transfer/types.ts
@@ -11967,21 +12370,21 @@ function normalizeForDedupe(s) {
11967
12370
  }
11968
12371
  async function importJsonBundle(opts) {
11969
12372
  const conflict = opts.conflict ?? "skip";
11970
- const fromDirAbs = path26.resolve(opts.fromDir);
11971
- const bundlePath = path26.join(fromDirAbs, "bundle.json");
12373
+ const fromDirAbs = path27.resolve(opts.fromDir);
12374
+ const bundlePath = path27.join(fromDirAbs, "bundle.json");
11972
12375
  const bundle = ExportBundleV1Schema.parse(await readJsonFile(bundlePath));
11973
- const memDirAbs = path26.resolve(opts.targetMemoryDir);
12376
+ const memDirAbs = path27.resolve(opts.targetMemoryDir);
11974
12377
  const written = [];
11975
12378
  let skipped = 0;
11976
12379
  for (const rec of bundle.records) {
11977
12380
  const isWorkspace = rec.path.startsWith("workspace/");
11978
- const targetBase = isWorkspace ? opts.workspaceDir ? path26.resolve(opts.workspaceDir) : null : memDirAbs;
12381
+ const targetBase = isWorkspace ? opts.workspaceDir ? path27.resolve(opts.workspaceDir) : null : memDirAbs;
11979
12382
  if (isWorkspace && !targetBase) {
11980
12383
  skipped += 1;
11981
12384
  continue;
11982
12385
  }
11983
12386
  const relFs = fromPosixRelPath(isWorkspace ? rec.path.replace(/^workspace\//, "") : rec.path);
11984
- const absTarget = path26.join(targetBase, relFs);
12387
+ const absTarget = path27.join(targetBase, relFs);
11985
12388
  const exists3 = await fileExists(absTarget);
11986
12389
  if (exists3) {
11987
12390
  if (conflict === "skip") {
@@ -12005,21 +12408,21 @@ async function importJsonBundle(opts) {
12005
12408
  return { written: 0, skipped };
12006
12409
  }
12007
12410
  for (const w of written) {
12008
- await mkdir19(path26.dirname(w.abs), { recursive: true });
12411
+ await mkdir19(path27.dirname(w.abs), { recursive: true });
12009
12412
  await writeFile17(w.abs, w.content, "utf-8");
12010
12413
  }
12011
12414
  return { written: written.length, skipped };
12012
12415
  }
12013
12416
  function looksLikeEngramJsonExport(fromDir) {
12014
- const dir = path26.resolve(fromDir);
12417
+ const dir = path27.resolve(fromDir);
12015
12418
  return Promise.all([
12016
- fileExists(path26.join(dir, "manifest.json")),
12017
- fileExists(path26.join(dir, "bundle.json"))
12419
+ fileExists(path27.join(dir, "manifest.json")),
12420
+ fileExists(path27.join(dir, "bundle.json"))
12018
12421
  ]).then(([m, b]) => m && b);
12019
12422
  }
12020
12423
 
12021
12424
  // src/transfer/import-sqlite.ts
12022
- import path27 from "path";
12425
+ import path28 from "path";
12023
12426
  import Database2 from "better-sqlite3";
12024
12427
  import { mkdir as mkdir20, writeFile as writeFile18 } from "fs/promises";
12025
12428
  function normalizeForDedupe2(s) {
@@ -12027,8 +12430,8 @@ function normalizeForDedupe2(s) {
12027
12430
  }
12028
12431
  async function importSqlite(opts) {
12029
12432
  const conflict = opts.conflict ?? "skip";
12030
- const memDirAbs = path27.resolve(opts.targetMemoryDir);
12031
- const fromAbs = path27.resolve(opts.fromFile);
12433
+ const memDirAbs = path28.resolve(opts.targetMemoryDir);
12434
+ const fromAbs = path28.resolve(opts.fromFile);
12032
12435
  const db = new Database2(fromAbs, { readonly: true });
12033
12436
  const written = [];
12034
12437
  let skipped = 0;
@@ -12041,7 +12444,7 @@ async function importSqlite(opts) {
12041
12444
  const rows = db.prepare("SELECT path_rel, content FROM files").all();
12042
12445
  for (const r of rows) {
12043
12446
  const relFs = fromPosixRelPath(r.path_rel);
12044
- const absTarget = path27.join(memDirAbs, relFs);
12447
+ const absTarget = path28.join(memDirAbs, relFs);
12045
12448
  const exists3 = await fileExists(absTarget);
12046
12449
  if (exists3) {
12047
12450
  if (conflict === "skip") {
@@ -12066,29 +12469,29 @@ async function importSqlite(opts) {
12066
12469
  }
12067
12470
  if (opts.dryRun) return { written: 0, skipped };
12068
12471
  for (const w of written) {
12069
- await mkdir20(path27.dirname(w.abs), { recursive: true });
12472
+ await mkdir20(path28.dirname(w.abs), { recursive: true });
12070
12473
  await writeFile18(w.abs, w.content, "utf-8");
12071
12474
  }
12072
12475
  return { written: written.length, skipped };
12073
12476
  }
12074
12477
 
12075
12478
  // src/transfer/import-md.ts
12076
- import path28 from "path";
12479
+ import path29 from "path";
12077
12480
  import { mkdir as mkdir21, readFile as readFile19, writeFile as writeFile19 } from "fs/promises";
12078
12481
  function normalizeForDedupe3(s) {
12079
12482
  return s.replace(/\s+/g, " ").trim();
12080
12483
  }
12081
12484
  async function importMarkdownBundle(opts) {
12082
12485
  const conflict = opts.conflict ?? "skip";
12083
- const fromAbs = path28.resolve(opts.fromDir);
12084
- const targetAbs = path28.resolve(opts.targetMemoryDir);
12486
+ const fromAbs = path29.resolve(opts.fromDir);
12487
+ const targetAbs = path29.resolve(opts.targetMemoryDir);
12085
12488
  const filesAbs = await listFilesRecursive(fromAbs);
12086
12489
  const writes = [];
12087
12490
  let skipped = 0;
12088
12491
  for (const abs of filesAbs) {
12089
12492
  const relPosix = toPosixRelPath(abs, fromAbs);
12090
12493
  if (relPosix === "manifest.json") continue;
12091
- const dstAbs = path28.join(targetAbs, fromPosixRelPath(relPosix));
12494
+ const dstAbs = path29.join(targetAbs, fromPosixRelPath(relPosix));
12092
12495
  const content = await readFile19(abs, "utf-8");
12093
12496
  const exists3 = await fileExists(dstAbs);
12094
12497
  if (exists3) {
@@ -12111,17 +12514,17 @@ async function importMarkdownBundle(opts) {
12111
12514
  }
12112
12515
  if (opts.dryRun) return { written: 0, skipped };
12113
12516
  for (const w of writes) {
12114
- await mkdir21(path28.dirname(w.abs), { recursive: true });
12517
+ await mkdir21(path29.dirname(w.abs), { recursive: true });
12115
12518
  await writeFile19(w.abs, w.content, "utf-8");
12116
12519
  }
12117
12520
  return { written: writes.length, skipped };
12118
12521
  }
12119
12522
 
12120
12523
  // src/transfer/autodetect.ts
12121
- import path29 from "path";
12524
+ import path30 from "path";
12122
12525
  import { stat as stat4 } from "fs/promises";
12123
12526
  async function detectImportFormat(fromPath) {
12124
- const abs = path29.resolve(fromPath);
12527
+ const abs = path30.resolve(fromPath);
12125
12528
  let st;
12126
12529
  try {
12127
12530
  st = await stat4(abs);
@@ -12163,7 +12566,7 @@ async function resolveMemoryDirForNamespace(orchestrator, namespace) {
12163
12566
  const ns = (namespace ?? "").trim();
12164
12567
  if (!ns) return orchestrator.config.memoryDir;
12165
12568
  if (!orchestrator.config.namespacesEnabled) return orchestrator.config.memoryDir;
12166
- const candidate = path30.join(orchestrator.config.memoryDir, "namespaces", ns);
12569
+ const candidate = path31.join(orchestrator.config.memoryDir, "namespaces", ns);
12167
12570
  if (ns === orchestrator.config.defaultNamespace) {
12168
12571
  return await exists2(candidate) ? candidate : orchestrator.config.memoryDir;
12169
12572
  }
@@ -12446,7 +12849,7 @@ function registerCli(api, orchestrator) {
12446
12849
  }
12447
12850
  });
12448
12851
  cmd.command("identity").description("Show agent identity reflections").action(async () => {
12449
- const workspaceDir = path30.join(process.env.HOME ?? "~", ".openclaw", "workspace");
12852
+ const workspaceDir = path31.join(process.env.HOME ?? "~", ".openclaw", "workspace");
12450
12853
  const identity = await orchestrator.storage.readIdentity(workspaceDir);
12451
12854
  if (!identity) {
12452
12855
  console.log("No identity file found.");
@@ -12586,8 +12989,8 @@ function registerCli(api, orchestrator) {
12586
12989
  const options = args[0] ?? {};
12587
12990
  const threadId = options.thread;
12588
12991
  const top = parseInt(options.top ?? "10", 10);
12589
- const memoryDir = path30.join(process.env.HOME ?? "~", ".openclaw", "workspace", "memory", "local");
12590
- const threading = new ThreadingManager(path30.join(memoryDir, "threads"));
12992
+ const memoryDir = path31.join(process.env.HOME ?? "~", ".openclaw", "workspace", "memory", "local");
12993
+ const threading = new ThreadingManager(path31.join(memoryDir, "threads"));
12591
12994
  if (threadId) {
12592
12995
  const thread = await threading.loadThread(threadId);
12593
12996
  if (!thread) {
@@ -12761,15 +13164,15 @@ function parseDuration(duration) {
12761
13164
 
12762
13165
  // src/index.ts
12763
13166
  import { readFile as readFile21, writeFile as writeFile20 } from "fs/promises";
12764
- import { readFileSync as readFileSync3 } from "fs";
12765
- import path31 from "path";
13167
+ import { readFileSync as readFileSync4 } from "fs";
13168
+ import path32 from "path";
12766
13169
  import os5 from "os";
12767
13170
  function loadPluginConfigFromFile() {
12768
13171
  try {
12769
13172
  const explicitConfigPath = process.env.OPENCLAW_ENGRAM_CONFIG_PATH || process.env.OPENCLAW_CONFIG_PATH;
12770
13173
  const homeDir = process.env.HOME ?? os5.homedir();
12771
- const configPath = explicitConfigPath && explicitConfigPath.length > 0 ? explicitConfigPath : path31.join(homeDir, ".openclaw", "openclaw.json");
12772
- const content = readFileSync3(configPath, "utf-8");
13174
+ const configPath = explicitConfigPath && explicitConfigPath.length > 0 ? explicitConfigPath : path32.join(homeDir, ".openclaw", "openclaw.json");
13175
+ const content = readFileSync4(configPath, "utf-8");
12773
13176
  const config = JSON.parse(content);
12774
13177
  const pluginEntry = config?.plugins?.entries?.["openclaw-engram"];
12775
13178
  return pluginEntry?.config;
@@ -12925,7 +13328,7 @@ Use this context naturally when relevant. Never quote or expose this memory cont
12925
13328
  );
12926
13329
  async function ensureHourlySummaryCron(api2) {
12927
13330
  const jobId = "engram-hourly-summary";
12928
- const cronFilePath = path31.join(os5.homedir(), ".openclaw", "cron", "jobs.json");
13331
+ const cronFilePath = path32.join(os5.homedir(), ".openclaw", "cron", "jobs.json");
12929
13332
  try {
12930
13333
  let jobsData = { version: 1, jobs: [] };
12931
13334
  try {