@remnic/plugin-openclaw 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,15 @@
1
+ import {
2
+ createVersion
3
+ } from "./chunk-6OJAU466.js";
1
4
  import {
2
5
  log
3
6
  } from "./chunk-UFU5GGGA.js";
4
7
 
5
8
  // ../remnic-core/src/storage.ts
6
- import { access as access2, readdir, readFile as readFile3, stat as stat2, writeFile as writeFile3, mkdir as mkdir3, unlink as unlink2, rename, appendFile } from "fs/promises";
9
+ import { access, readdir, readFile as readFile2, stat as stat2, writeFile as writeFile2, mkdir as mkdir2, unlink, rename, appendFile } from "fs/promises";
7
10
  import { appendFileSync, mkdirSync, statSync } from "fs";
8
- import { createHash as createHash2 } from "crypto";
9
- import path5 from "path";
11
+ import { createHash } from "crypto";
12
+ import path4 from "path";
10
13
 
11
14
  // ../remnic-core/src/memory-cache.ts
12
15
  var entityCacheByDir = /* @__PURE__ */ new Map();
@@ -173,128 +176,24 @@ function sanitizeMemoryContent(text) {
173
176
  };
174
177
  }
175
178
 
176
- // ../remnic-core/src/page-versioning.ts
177
- import { createHash } from "crypto";
178
- import path2 from "path";
179
- import {
180
- access,
181
- mkdir as mkdir2,
182
- readFile as readFile2,
183
- writeFile as writeFile2,
184
- unlink
185
- } from "fs/promises";
186
- var NOOP_LOGGER = {
187
- debug: () => {
188
- },
189
- warn: () => {
190
- }
191
- };
192
- var writeLocks = /* @__PURE__ */ new Map();
193
- function withPageLock(pageKey, fn) {
194
- const prev = writeLocks.get(pageKey) ?? Promise.resolve();
195
- const next = prev.then(fn, fn);
196
- writeLocks.set(pageKey, next.then(() => {
197
- }, () => {
198
- }));
199
- return next;
200
- }
201
- function contentHash(content) {
202
- return createHash("sha256").update(content, "utf-8").digest("hex");
203
- }
204
- function sidecarKey(pagePath) {
205
- const withoutExt = pagePath.replace(/\.md$/i, "");
206
- return withoutExt.replace(/[\\/]/g, "__");
207
- }
208
- function sidecarDir(memoryDir, sidecar, pagePath) {
209
- return path2.join(memoryDir, sidecar, sidecarKey(pagePath));
210
- }
211
- function manifestPath(memoryDir, sidecar, pagePath) {
212
- return path2.join(sidecarDir(memoryDir, sidecar, pagePath), "manifest.json");
213
- }
214
- async function readManifest(memoryDir, sidecar, pagePath) {
215
- const mp = manifestPath(memoryDir, sidecar, pagePath);
216
- try {
217
- const raw = await readFile2(mp, "utf-8");
218
- const parsed = JSON.parse(raw);
219
- if (typeof parsed !== "object" || parsed === null) {
220
- return { pagePath, versions: [], currentVersion: "0" };
221
- }
222
- const obj = parsed;
223
- const versions = Array.isArray(obj.versions) ? obj.versions : [];
224
- const currentVersion = typeof obj.currentVersion === "string" ? obj.currentVersion : "0";
225
- return { pagePath: typeof obj.pagePath === "string" ? obj.pagePath : pagePath, versions, currentVersion };
226
- } catch {
227
- return { pagePath, versions: [], currentVersion: "0" };
228
- }
229
- }
230
- async function writeManifest(memoryDir, sidecar, pagePath, history) {
231
- const dir = sidecarDir(memoryDir, sidecar, pagePath);
232
- await mkdir2(dir, { recursive: true });
233
- const mp = manifestPath(memoryDir, sidecar, pagePath);
234
- await writeFile2(mp, JSON.stringify(history, null, 2) + "\n", "utf-8");
235
- }
236
- async function createVersion(pagePath, content, trigger, config, log2 = NOOP_LOGGER, note, memoryDir) {
237
- const { sidecarDir: sidecar, maxVersionsPerPage } = config;
238
- const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
239
- const mPath = manifestPath(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
240
- return withPageLock(mPath, async () => {
241
- const history = await readManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
242
- const nextId = String(history.versions.length > 0 ? Math.max(...history.versions.map((v) => Number(v.versionId))) + 1 : 1);
243
- const hash = contentHash(content);
244
- const version = {
245
- versionId: nextId,
246
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
247
- contentHash: hash,
248
- sizeBytes: Buffer.byteLength(content, "utf-8"),
249
- trigger,
250
- ...note !== void 0 ? { note } : {}
251
- };
252
- const dir = sidecarDir(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
253
- await mkdir2(dir, { recursive: true });
254
- const ext = path2.extname(pagePath) || ".md";
255
- const snapshotPath = path2.join(dir, `${nextId}${ext}`);
256
- await writeFile2(snapshotPath, content, "utf-8");
257
- history.versions.push(version);
258
- history.currentVersion = nextId;
259
- if (maxVersionsPerPage > 0 && history.versions.length > maxVersionsPerPage) {
260
- const toRemove = history.versions.splice(0, history.versions.length - maxVersionsPerPage);
261
- for (const old of toRemove) {
262
- const oldPath = path2.join(dir, `${old.versionId}${ext}`);
263
- try {
264
- await unlink(oldPath);
265
- } catch {
266
- log2.debug(`page-versioning: could not remove old snapshot ${oldPath}`);
267
- }
268
- }
269
- }
270
- await writeManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir), history);
271
- log2.debug(`page-versioning: created version ${nextId} for ${pagePath} (trigger=${trigger})`);
272
- return version;
273
- });
274
- }
275
- function resolveMemoryDir(pagePath) {
276
- const knownSubdirs = /* @__PURE__ */ new Set([
277
- "facts",
278
- "corrections",
279
- "entities",
280
- "state",
281
- "artifacts",
282
- "questions",
283
- "profiles"
284
- ]);
285
- let dir = path2.dirname(pagePath);
286
- for (let depth = 0; depth < 5; depth++) {
287
- const base = path2.basename(dir);
288
- if (knownSubdirs.has(base) || /^\d{4}-\d{2}-\d{2}$/.test(base)) {
289
- dir = path2.dirname(dir);
290
- } else {
291
- break;
292
- }
293
- }
294
- return dir;
295
- }
296
- function relPath(pagePath, memoryDir) {
297
- return path2.relative(memoryDir, pagePath);
179
+ // ../remnic-core/src/consolidation-operator.ts
180
+ var CONSOLIDATION_OPERATORS = [
181
+ "split",
182
+ "merge",
183
+ "update"
184
+ ];
185
+ var DERIVED_FROM_ENTRY_RE = /^(.+):(\d+)$/;
186
+ function isValidDerivedFromEntry(entry) {
187
+ if (typeof entry !== "string") return false;
188
+ const match = entry.match(DERIVED_FROM_ENTRY_RE);
189
+ if (!match) return false;
190
+ const pathPart = match[1];
191
+ if (pathPart.length === 0 || pathPart.trim().length === 0) return false;
192
+ const versionNum = Number(match[2]);
193
+ return Number.isInteger(versionNum) && versionNum >= 0;
194
+ }
195
+ function isConsolidationOperator(value) {
196
+ return typeof value === "string" && CONSOLIDATION_OPERATORS.includes(value);
298
197
  }
299
198
 
300
199
  // ../remnic-core/src/entity-schema.ts
@@ -651,7 +550,7 @@ function confidenceTier(score) {
651
550
  var SPECULATIVE_TTL_DAYS = 30;
652
551
 
653
552
  // ../remnic-core/src/memory-projection-store.ts
654
- import path3 from "path";
553
+ import path2 from "path";
655
554
  import { readFileSync } from "fs";
656
555
 
657
556
  // ../remnic-core/src/runtime/better-sqlite.ts
@@ -684,7 +583,7 @@ function openBetterSqlite3(file, options) {
684
583
  // ../remnic-core/src/memory-projection-store.ts
685
584
  var MEMORY_PROJECTION_SCHEMA_VERSION = 2;
686
585
  function getMemoryProjectionPath(memoryDir) {
687
- return path3.join(memoryDir, "state", "memory-projection.sqlite");
586
+ return path2.join(memoryDir, "state", "memory-projection.sqlite");
688
587
  }
689
588
  function listTableColumns(db, tableName) {
690
589
  try {
@@ -916,7 +815,7 @@ function parseCurrentRow(memoryDir, row) {
916
815
  category: row.category,
917
816
  status: row.status,
918
817
  lifecycleState: typeof row.lifecycle_state === "string" ? row.lifecycle_state : void 0,
919
- path: path3.join(memoryDir, row.path_rel),
818
+ path: path2.join(memoryDir, row.path_rel),
920
819
  pathRel: row.path_rel,
921
820
  created: row.created_at,
922
821
  updated: row.updated_at,
@@ -1077,7 +976,7 @@ function readProjectedMemoryBrowse(memoryDir, options) {
1077
976
  return true;
1078
977
  }
1079
978
  try {
1080
- const filePath = path3.join(memoryDir, row.path_rel);
979
+ const filePath = path2.join(memoryDir, row.path_rel);
1081
980
  const content = readFileSync(filePath, "utf-8").toLowerCase();
1082
981
  return content.includes(normalizedQuery);
1083
982
  } catch {
@@ -1091,7 +990,7 @@ function readProjectedMemoryBrowse(memoryDir, options) {
1091
990
  (row) => typeof row.memory_id === "string" && typeof row.path_rel === "string" && typeof row.category === "string" && typeof row.status === "string"
1092
991
  ).map((row) => ({
1093
992
  id: row.memory_id,
1094
- path: path3.join(memoryDir, row.path_rel),
993
+ path: path2.join(memoryDir, row.path_rel),
1095
994
  category: row.category,
1096
995
  status: row.status,
1097
996
  created: typeof row.created_at === "string" ? row.created_at : void 0,
@@ -1125,7 +1024,7 @@ function readProjectedMemoryBrowse(memoryDir, options) {
1125
1024
  (row) => typeof row.memory_id === "string" && typeof row.path_rel === "string" && typeof row.category === "string" && typeof row.status === "string"
1126
1025
  ).map((row) => ({
1127
1026
  id: row.memory_id,
1128
- path: path3.join(memoryDir, row.path_rel),
1027
+ path: path2.join(memoryDir, row.path_rel),
1129
1028
  category: row.category,
1130
1029
  status: row.status,
1131
1030
  created: typeof row.created_at === "string" ? row.created_at : void 0,
@@ -1341,7 +1240,7 @@ function readProjectedGovernanceRecord(memoryDir) {
1341
1240
  }
1342
1241
 
1343
1242
  // ../remnic-core/src/memory-lifecycle-ledger-utils.ts
1344
- import path4 from "path";
1243
+ import path3 from "path";
1345
1244
  var MEMORY_LIFECYCLE_RULE_VERSION = "memory-lifecycle-ledger.v1";
1346
1245
  var MEMORY_LIFECYCLE_EVENT_SORT_ORDER = {
1347
1246
  created: 0,
@@ -1357,8 +1256,8 @@ var MEMORY_LIFECYCLE_EVENT_SORT_ORDER = {
1357
1256
  archived: 10
1358
1257
  };
1359
1258
  function toMemoryPathRel(baseDir, filePath) {
1360
- if (!baseDir) return filePath.split(path4.sep).join("/");
1361
- return path4.relative(baseDir, filePath).split(path4.sep).join("/");
1259
+ if (!baseDir) return filePath.split(path3.sep).join("/");
1260
+ return path3.relative(baseDir, filePath).split(path3.sep).join("/");
1362
1261
  }
1363
1262
  function isArchivedMemoryPath(pathRel) {
1364
1263
  return pathRel === "archive" || pathRel.startsWith("archive/");
@@ -1722,6 +1621,17 @@ var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
1722
1621
  function tokenizeArtifactSearchText(input) {
1723
1622
  return input.toLowerCase().split(/[^a-z0-9]+/i).map((t) => t.trim()).filter((t) => t.length >= 2).filter((t) => !ARTIFACT_SEARCH_STOPWORDS.has(t));
1724
1623
  }
1624
+ function assertMemoryWorthCounter(field, value) {
1625
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1626
+ throw new Error(`${field} must be a finite number, got ${String(value)}`);
1627
+ }
1628
+ if (!Number.isInteger(value)) {
1629
+ throw new Error(`${field} must be an integer, got ${value}`);
1630
+ }
1631
+ if (value < 0) {
1632
+ throw new Error(`${field} must be >= 0, got ${value}`);
1633
+ }
1634
+ }
1725
1635
  function serializeFrontmatter(fm) {
1726
1636
  const lines = [
1727
1637
  "---",
@@ -1754,6 +1664,14 @@ function serializeFrontmatter(fm) {
1754
1664
  lines.push(`accessCount: ${fm.accessCount}`);
1755
1665
  }
1756
1666
  if (fm.lastAccessed) lines.push(`lastAccessed: ${fm.lastAccessed}`);
1667
+ if (fm.mw_success !== void 0) {
1668
+ assertMemoryWorthCounter("mw_success", fm.mw_success);
1669
+ lines.push(`mw_success: ${fm.mw_success}`);
1670
+ }
1671
+ if (fm.mw_fail !== void 0) {
1672
+ assertMemoryWorthCounter("mw_fail", fm.mw_fail);
1673
+ lines.push(`mw_fail: ${fm.mw_fail}`);
1674
+ }
1757
1675
  if (fm.importance) {
1758
1676
  lines.push(`importanceScore: ${fm.importance.score}`);
1759
1677
  lines.push(`importanceLevel: ${fm.importance.level}`);
@@ -1791,6 +1709,33 @@ function serializeFrontmatter(fm) {
1791
1709
  lines.push(`structuredAttributes: ${JSON.stringify(fm.structuredAttributes)}`);
1792
1710
  }
1793
1711
  if (fm.contentHash) lines.push(`contentHash: ${fm.contentHash}`);
1712
+ if (fm.derived_from !== void 0) {
1713
+ if (!Array.isArray(fm.derived_from)) {
1714
+ throw new Error(
1715
+ `serializeFrontmatter: derived_from must be an array of "<path>:<version>" strings`
1716
+ );
1717
+ }
1718
+ for (const entry of fm.derived_from) {
1719
+ if (!isValidDerivedFromEntry(entry)) {
1720
+ throw new Error(
1721
+ `serializeFrontmatter: invalid derived_from entry ${JSON.stringify(entry)} \u2014 expected "<path>:<version>" with version >= 0`
1722
+ );
1723
+ }
1724
+ }
1725
+ if (fm.derived_from.length > 0) {
1726
+ lines.push(
1727
+ `derived_from: [${fm.derived_from.map((e) => `"${e.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join(", ")}]`
1728
+ );
1729
+ }
1730
+ }
1731
+ if (fm.derived_via !== void 0) {
1732
+ if (!isConsolidationOperator(fm.derived_via)) {
1733
+ throw new Error(
1734
+ `serializeFrontmatter: invalid derived_via ${JSON.stringify(fm.derived_via)} \u2014 expected one of "split" | "merge" | "update"`
1735
+ );
1736
+ }
1737
+ lines.push(`derived_via: ${fm.derived_via}`);
1738
+ }
1794
1739
  lines.push("---");
1795
1740
  return lines.join("\n");
1796
1741
  }
@@ -1823,13 +1768,54 @@ function parseLinkReasonValue(rawValue) {
1823
1768
  return legacyValue;
1824
1769
  }
1825
1770
  }
1771
+ function parseMemoryWorthCounterField(raw) {
1772
+ if (raw === void 0) return void 0;
1773
+ const trimmed = raw.trim();
1774
+ if (trimmed.length === 0) return void 0;
1775
+ const n = Number(trimmed);
1776
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) return void 0;
1777
+ return n;
1778
+ }
1826
1779
  function parseFrontmatter2(raw) {
1827
1780
  const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
1828
1781
  if (!match) return null;
1829
1782
  const fmBlock = match[1];
1830
1783
  const content = match[2].trim();
1831
1784
  const fm = {};
1832
- for (const line of fmBlock.split("\n")) {
1785
+ const rawLines = fmBlock.split("\n");
1786
+ const lines = [];
1787
+ let i = 0;
1788
+ while (i < rawLines.length) {
1789
+ const line = rawLines[i];
1790
+ const colonIdx = line.indexOf(":");
1791
+ if (colonIdx !== -1 && line.slice(colonIdx + 1).trim() === "") {
1792
+ const baseIndent = line.match(/^\s*/)[0].length;
1793
+ const items = [];
1794
+ let j = i + 1;
1795
+ while (j < rawLines.length) {
1796
+ const next = rawLines[j];
1797
+ const m = next.match(/^(\s+)- (.*)$/);
1798
+ if (!m || m[1].length <= baseIndent) break;
1799
+ let item = m[2].trim();
1800
+ if (item.startsWith('"') && item.endsWith('"') && item.length >= 2) {
1801
+ item = item.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
1802
+ } else if (item.startsWith("'") && item.endsWith("'") && item.length >= 2) {
1803
+ item = item.slice(1, -1).replace(/''/g, "'");
1804
+ }
1805
+ items.push(item);
1806
+ j++;
1807
+ }
1808
+ if (items.length > 0) {
1809
+ const inline = items.map((v) => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join(", ");
1810
+ lines.push(`${line.slice(0, colonIdx + 1)} [${inline}]`);
1811
+ i = j;
1812
+ continue;
1813
+ }
1814
+ }
1815
+ lines.push(line);
1816
+ i++;
1817
+ }
1818
+ for (const line of lines) {
1833
1819
  const colonIdx = line.indexOf(":");
1834
1820
  if (colonIdx === -1) continue;
1835
1821
  const key = line.slice(0, colonIdx).trim();
@@ -1855,9 +1841,84 @@ function parseFrontmatter2(raw) {
1855
1841
  if (lineageMatch) {
1856
1842
  lineage = lineageMatch[1].split(",").map((l) => l.trim().replace(/^"|"$/g, "")).filter(Boolean);
1857
1843
  }
1844
+ let derived_from;
1845
+ const derivedFromStr = (fm.derived_from ?? "").trim();
1846
+ if (derivedFromStr.startsWith("[") && derivedFromStr.endsWith("]")) {
1847
+ const inner = derivedFromStr.slice(1, -1);
1848
+ const entries = [];
1849
+ let i2 = 0;
1850
+ while (i2 < inner.length) {
1851
+ const ch = inner[i2];
1852
+ if (ch === '"') {
1853
+ let buf = "";
1854
+ i2++;
1855
+ while (i2 < inner.length) {
1856
+ const c = inner[i2];
1857
+ if (c === "\\" && i2 + 1 < inner.length) {
1858
+ const next = inner[i2 + 1];
1859
+ if (next === '"') {
1860
+ buf += '"';
1861
+ i2 += 2;
1862
+ continue;
1863
+ }
1864
+ if (next === "\\") {
1865
+ buf += "\\";
1866
+ i2 += 2;
1867
+ continue;
1868
+ }
1869
+ buf += c;
1870
+ i2++;
1871
+ continue;
1872
+ }
1873
+ if (c === '"') {
1874
+ i2++;
1875
+ break;
1876
+ }
1877
+ buf += c;
1878
+ i2++;
1879
+ }
1880
+ if (buf.length > 0) entries.push(buf);
1881
+ } else if (ch === "'") {
1882
+ let buf = "";
1883
+ i2++;
1884
+ while (i2 < inner.length) {
1885
+ const c = inner[i2];
1886
+ if (c === "'") {
1887
+ if (i2 + 1 < inner.length && inner[i2 + 1] === "'") {
1888
+ buf += "'";
1889
+ i2 += 2;
1890
+ continue;
1891
+ }
1892
+ i2++;
1893
+ break;
1894
+ }
1895
+ buf += c;
1896
+ i2++;
1897
+ }
1898
+ if (buf.length > 0) entries.push(buf);
1899
+ } else if (ch === "," || /\s/.test(ch)) {
1900
+ i2++;
1901
+ } else {
1902
+ let buf = "";
1903
+ while (i2 < inner.length) {
1904
+ const c = inner[i2];
1905
+ if (c === "," || /\s/.test(c)) break;
1906
+ buf += c;
1907
+ i2++;
1908
+ }
1909
+ if (buf.length > 0) entries.push(buf);
1910
+ }
1911
+ }
1912
+ if (entries.length > 0) derived_from = entries;
1913
+ }
1914
+ const derivedViaRaw = (fm.derived_via ?? "").trim();
1915
+ const derivedViaUnquoted = derivedViaRaw.startsWith('"') && derivedViaRaw.endsWith('"') || derivedViaRaw.startsWith("'") && derivedViaRaw.endsWith("'") ? derivedViaRaw.slice(1, -1) : derivedViaRaw;
1916
+ const derived_via = isConsolidationOperator(derivedViaUnquoted) ? derivedViaUnquoted : void 0;
1858
1917
  const accessCount = fm.accessCount ? parseInt(fm.accessCount, 10) : void 0;
1859
1918
  const decayScore = fm.decayScore !== void 0 ? parseFloat(fm.decayScore) : void 0;
1860
1919
  const heatScore = fm.heatScore !== void 0 ? parseFloat(fm.heatScore) : void 0;
1920
+ const mw_success = parseMemoryWorthCounterField(fm.mw_success);
1921
+ const mw_fail = parseMemoryWorthCounterField(fm.mw_fail);
1861
1922
  let importance;
1862
1923
  if (fm.importanceScore) {
1863
1924
  const score = parseFloat(fm.importanceScore);
@@ -1909,6 +1970,9 @@ function parseFrontmatter2(raw) {
1909
1970
  // Access tracking
1910
1971
  accessCount: accessCount && accessCount > 0 ? accessCount : void 0,
1911
1972
  lastAccessed: fm.lastAccessed || void 0,
1973
+ // Memory Worth counters (issue #560)
1974
+ mw_success,
1975
+ mw_fail,
1912
1976
  // Importance scoring
1913
1977
  importance,
1914
1978
  // Chunking
@@ -1927,7 +1991,11 @@ function parseFrontmatter2(raw) {
1927
1991
  // Structured attributes (JSON on a single line)
1928
1992
  structuredAttributes: parseStructuredAttributes(fm.structuredAttributes),
1929
1993
  // Raw-content dedup hash (format-agnostic archive/consolidation cleanup)
1930
- contentHash: fm.contentHash || void 0
1994
+ contentHash: fm.contentHash || void 0,
1995
+ // Consolidation provenance (issue #561) — read-through only in this
1996
+ // PR; no code produces these fields yet.
1997
+ derived_from,
1998
+ derived_via
1931
1999
  },
1932
2000
  content
1933
2001
  };
@@ -1964,17 +2032,17 @@ var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set([
1964
2032
  "topic"
1965
2033
  ]);
1966
2034
  function inferEntityTypeFromFilename(pathRel) {
1967
- const basename = path5.basename(pathRel, ".md").toLowerCase();
2035
+ const basename = path4.basename(pathRel, ".md").toLowerCase();
1968
2036
  const separator = basename.indexOf("-");
1969
2037
  if (separator <= 0) return void 0;
1970
2038
  const candidate = basename.slice(0, separator);
1971
2039
  return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
1972
2040
  }
1973
2041
  function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
1974
- const normalizedPath = pathRel.split(path5.sep).join("/");
2042
+ const normalizedPath = pathRel.split(path4.sep).join("/");
1975
2043
  let normalizedFrontmatter = frontmatter;
1976
2044
  if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
1977
- const basename = path5.basename(pathRel, ".md");
2045
+ const basename = path4.basename(pathRel, ".md");
1978
2046
  const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
1979
2047
  const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
1980
2048
  normalizedFrontmatter = {
@@ -2039,12 +2107,12 @@ var ContentHashIndex = class _ContentHashIndex {
2039
2107
  dirty = false;
2040
2108
  filePath;
2041
2109
  constructor(stateDir) {
2042
- this.filePath = path5.join(stateDir, "fact-hashes.txt");
2110
+ this.filePath = path4.join(stateDir, "fact-hashes.txt");
2043
2111
  }
2044
2112
  /** Load existing hashes from disk. Safe to call multiple times. */
2045
2113
  async load() {
2046
2114
  try {
2047
- const raw = await readFile3(this.filePath, "utf-8");
2115
+ const raw = await readFile2(this.filePath, "utf-8");
2048
2116
  for (const line of raw.split("\n")) {
2049
2117
  const trimmed = line.trim();
2050
2118
  if (trimmed.length > 0) {
@@ -2074,8 +2142,8 @@ var ContentHashIndex = class _ContentHashIndex {
2074
2142
  /** Persist index to disk if changed. */
2075
2143
  async save() {
2076
2144
  if (!this.dirty) return;
2077
- await mkdir3(path5.dirname(this.filePath), { recursive: true });
2078
- await writeFile3(this.filePath, [...this.hashes].join("\n") + "\n", "utf-8");
2145
+ await mkdir2(path4.dirname(this.filePath), { recursive: true });
2146
+ await writeFile2(this.filePath, [...this.hashes].join("\n") + "\n", "utf-8");
2079
2147
  this.dirty = false;
2080
2148
  log.debug(`content-hash index: saved ${this.hashes.size} hashes`);
2081
2149
  }
@@ -2120,7 +2188,7 @@ var ContentHashIndex = class _ContentHashIndex {
2120
2188
  /** Normalize content and compute SHA-256 hash. */
2121
2189
  static computeHash(content) {
2122
2190
  const normalized = _ContentHashIndex.normalizeContent(content);
2123
- return createHash2("sha256").update(normalized).digest("hex");
2191
+ return createHash("sha256").update(normalized).digest("hex");
2124
2192
  }
2125
2193
  };
2126
2194
  function normalizeAttributePairs(pairs) {
@@ -2611,7 +2679,7 @@ function fingerprintEntityStructuredFacts(entity) {
2611
2679
  facts: normalizeStructuredSectionFacts(section.facts).slice().sort((left, right) => left.localeCompare(right))
2612
2680
  })).filter((section) => section.facts.length > 0).sort((left, right) => left.key.localeCompare(right.key) || left.title.localeCompare(right.title) || left.facts.join("\n").localeCompare(right.facts.join("\n")));
2613
2681
  if (normalizedSections.length === 0) return void 0;
2614
- return createHash2("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
2682
+ return createHash("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
2615
2683
  }
2616
2684
  function isEntitySynthesisStale(entity) {
2617
2685
  const structuredFactCount = countEntityStructuredFacts(entity);
@@ -2902,6 +2970,27 @@ function buildEntitySchemaCacheKey(entitySchemas) {
2902
2970
  ]);
2903
2971
  return JSON.stringify(normalized);
2904
2972
  }
2973
+ function isValidBufferSurpriseEvent(value) {
2974
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2975
+ const v = value;
2976
+ if (v.event !== "BUFFER_SURPRISE") return false;
2977
+ if (typeof v.timestamp !== "string" || v.timestamp.length === 0) return false;
2978
+ if (!Number.isFinite(Date.parse(v.timestamp))) return false;
2979
+ if (typeof v.bufferKey !== "string" || v.bufferKey.length === 0) return false;
2980
+ if (v.sessionKey !== null && typeof v.sessionKey !== "string") return false;
2981
+ if (v.turnRole !== "user" && v.turnRole !== "assistant") return false;
2982
+ if (typeof v.surpriseScore !== "number" || !Number.isFinite(v.surpriseScore)) {
2983
+ return false;
2984
+ }
2985
+ if (v.surpriseScore < 0 || v.surpriseScore > 1) return false;
2986
+ if (typeof v.threshold !== "number" || !Number.isFinite(v.threshold)) return false;
2987
+ if (v.threshold < 0 || v.threshold > 1) return false;
2988
+ if (typeof v.triggeredFlush !== "boolean") return false;
2989
+ if (typeof v.turnCountInWindow !== "number" || !Number.isFinite(v.turnCountInWindow)) {
2990
+ return false;
2991
+ }
2992
+ return true;
2993
+ }
2905
2994
  var StorageManager = class _StorageManager {
2906
2995
  constructor(baseDir, entitySchemas) {
2907
2996
  this.baseDir = baseDir;
@@ -2979,24 +3068,65 @@ var StorageManager = class _StorageManager {
2979
3068
  async snapshotBeforeWrite(filePath, trigger) {
2980
3069
  if (!this._versioningConfig || !this._versioningConfig.enabled) return;
2981
3070
  try {
2982
- const existing = await readFile3(filePath, "utf-8");
3071
+ const existing = await readFile2(filePath, "utf-8");
2983
3072
  await createVersion(filePath, existing, trigger, this._versioningConfig, log, void 0, this.baseDir);
2984
3073
  } catch {
2985
3074
  }
2986
3075
  }
3076
+ /**
3077
+ * Consolidation provenance helper (issue #561 PR 2).
3078
+ *
3079
+ * Captures the current on-disk content of a source memory as a
3080
+ * page-version snapshot so the downstream consolidated write can record a
3081
+ * `derived_from` pointer that actually resolves. Returns the
3082
+ * `"<relative-path>:<versionId>"` entry expected by the `derived_from`
3083
+ * frontmatter field.
3084
+ *
3085
+ * Returns `null` when versioning is disabled (snapshots would not be
3086
+ * created), when the file does not exist (nothing to snapshot), or when
3087
+ * the snapshot write itself fails (best-effort — callers skip the entry
3088
+ * rather than block the consolidation).
3089
+ */
3090
+ async snapshotForProvenance(filePath) {
3091
+ if (!this._versioningConfig || !this._versioningConfig.enabled) return null;
3092
+ let existing;
3093
+ try {
3094
+ existing = await readFile2(filePath, "utf-8");
3095
+ } catch {
3096
+ return null;
3097
+ }
3098
+ try {
3099
+ const version = await createVersion(
3100
+ filePath,
3101
+ existing,
3102
+ "consolidation",
3103
+ this._versioningConfig,
3104
+ log,
3105
+ void 0,
3106
+ this.baseDir
3107
+ );
3108
+ const rel = path4.relative(this.baseDir, filePath).split(path4.sep).join("/");
3109
+ return `${rel}:${version.versionId}`;
3110
+ } catch (err) {
3111
+ log.warn(
3112
+ `storage.snapshotForProvenance: failed to snapshot ${filePath}: ${err instanceof Error ? err.message : String(err)}`
3113
+ );
3114
+ return null;
3115
+ }
3116
+ }
2987
3117
  /** The root directory of this storage instance. */
2988
3118
  get dir() {
2989
3119
  return this.baseDir;
2990
3120
  }
2991
3121
  identityFilePath(workspaceDir, namespace) {
2992
3122
  const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
2993
- if (!rawNamespace) return path5.join(workspaceDir, "IDENTITY.md");
3123
+ if (!rawNamespace) return path4.join(workspaceDir, "IDENTITY.md");
2994
3124
  const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
2995
- return path5.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
3125
+ return path4.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
2996
3126
  }
2997
3127
  versionFilePath(kind) {
2998
3128
  const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : ".cold-write-version.log";
2999
- return path5.join(this.stateDir, fileName);
3129
+ return path4.join(this.stateDir, fileName);
3000
3130
  }
3001
3131
  bumpSharedVersion(kind, fallbackMap) {
3002
3132
  const filePath = this.versionFilePath(kind);
@@ -3033,25 +3163,28 @@ var StorageManager = class _StorageManager {
3033
3163
  return this.readSharedVersion("artifact-write", _StorageManager.artifactWriteVersionByDir);
3034
3164
  }
3035
3165
  get factsDir() {
3036
- return path5.join(this.baseDir, "facts");
3166
+ return path4.join(this.baseDir, "facts");
3037
3167
  }
3038
3168
  get correctionsDir() {
3039
- return path5.join(this.baseDir, "corrections");
3169
+ return path4.join(this.baseDir, "corrections");
3040
3170
  }
3041
3171
  get proceduresDir() {
3042
- return path5.join(this.baseDir, "procedures");
3172
+ return path4.join(this.baseDir, "procedures");
3173
+ }
3174
+ get reasoningTracesDir() {
3175
+ return path4.join(this.baseDir, "reasoning-traces");
3043
3176
  }
3044
3177
  get entitiesDir() {
3045
- return path5.join(this.baseDir, "entities");
3178
+ return path4.join(this.baseDir, "entities");
3046
3179
  }
3047
3180
  get stateDir() {
3048
- return path5.join(this.baseDir, "state");
3181
+ return path4.join(this.baseDir, "state");
3049
3182
  }
3050
3183
  get entitySynthesisQueuePath() {
3051
- return path5.join(this.stateDir, "entity-synthesis-queue.json");
3184
+ return path4.join(this.stateDir, "entity-synthesis-queue.json");
3052
3185
  }
3053
3186
  get factHashIndexReadyPath() {
3054
- return path5.join(this.stateDir, "fact-hashes.ready");
3187
+ return path4.join(this.stateDir, "fact-hashes.ready");
3055
3188
  }
3056
3189
  async getFactHashIndex() {
3057
3190
  if (this.factHashIndex) {
@@ -3079,7 +3212,7 @@ var StorageManager = class _StorageManager {
3079
3212
  }
3080
3213
  this.factHashIndexAuthoritativePromise = (async () => {
3081
3214
  try {
3082
- await access2(this.factHashIndexReadyPath);
3215
+ await access(this.factHashIndexReadyPath);
3083
3216
  this.factHashIndexAuthoritative = true;
3084
3217
  return;
3085
3218
  } catch {
@@ -3117,8 +3250,8 @@ var StorageManager = class _StorageManager {
3117
3250
  );
3118
3251
  }
3119
3252
  await factHashIndex.save();
3120
- await mkdir3(path5.dirname(this.factHashIndexReadyPath), { recursive: true });
3121
- await writeFile3(this.factHashIndexReadyPath, "v1\n", "utf-8");
3253
+ await mkdir2(path4.dirname(this.factHashIndexReadyPath), { recursive: true });
3254
+ await writeFile2(this.factHashIndexReadyPath, "v1\n", "utf-8");
3122
3255
  this.factHashIndexAuthoritative = true;
3123
3256
  })().finally(() => {
3124
3257
  this.factHashIndexAuthoritativePromise = null;
@@ -3126,55 +3259,68 @@ var StorageManager = class _StorageManager {
3126
3259
  await this.factHashIndexAuthoritativePromise;
3127
3260
  }
3128
3261
  get questionsDir() {
3129
- return path5.join(this.baseDir, "questions");
3262
+ return path4.join(this.baseDir, "questions");
3130
3263
  }
3131
3264
  get artifactsDir() {
3132
- return path5.join(this.baseDir, "artifacts");
3265
+ return path4.join(this.baseDir, "artifacts");
3133
3266
  }
3134
3267
  get identityDir() {
3135
- return path5.join(this.baseDir, "identity");
3268
+ return path4.join(this.baseDir, "identity");
3136
3269
  }
3137
3270
  get identityAnchorPath() {
3138
- return path5.join(this.identityDir, "identity-anchor.md");
3271
+ return path4.join(this.identityDir, "identity-anchor.md");
3139
3272
  }
3140
3273
  get identityIncidentsDir() {
3141
- return path5.join(this.identityDir, "incidents");
3274
+ return path4.join(this.identityDir, "incidents");
3142
3275
  }
3143
3276
  get identityAuditsWeeklyDir() {
3144
- return path5.join(this.identityDir, "audits", "weekly");
3277
+ return path4.join(this.identityDir, "audits", "weekly");
3145
3278
  }
3146
3279
  get identityAuditsMonthlyDir() {
3147
- return path5.join(this.identityDir, "audits", "monthly");
3280
+ return path4.join(this.identityDir, "audits", "monthly");
3148
3281
  }
3149
3282
  get identityImprovementLoopsPath() {
3150
- return path5.join(this.identityDir, "improvement-loops.md");
3283
+ return path4.join(this.identityDir, "improvement-loops.md");
3151
3284
  }
3152
3285
  get identityReflectionsPath() {
3153
- return path5.join(this.identityDir, "reflections.md");
3286
+ return path4.join(this.identityDir, "reflections.md");
3154
3287
  }
3155
3288
  get profilePath() {
3156
- return path5.join(this.baseDir, "profile.md");
3289
+ return path4.join(this.baseDir, "profile.md");
3157
3290
  }
3158
3291
  get memoryActionsPath() {
3159
- return path5.join(this.stateDir, "memory-actions.jsonl");
3292
+ return path4.join(this.stateDir, "memory-actions.jsonl");
3160
3293
  }
3161
3294
  get memoryLifecycleLedgerPath() {
3162
- return path5.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
3295
+ return path4.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
3163
3296
  }
3164
3297
  get compressionGuidelinesPath() {
3165
- return path5.join(this.stateDir, "compression-guidelines.md");
3298
+ return path4.join(this.stateDir, "compression-guidelines.md");
3166
3299
  }
3167
3300
  get compressionGuidelineDraftPath() {
3168
- return path5.join(this.stateDir, "compression-guidelines.draft.md");
3301
+ return path4.join(this.stateDir, "compression-guidelines.draft.md");
3169
3302
  }
3170
3303
  get compressionGuidelineStatePath() {
3171
- return path5.join(this.stateDir, "compression-guideline-state.json");
3304
+ return path4.join(this.stateDir, "compression-guideline-state.json");
3172
3305
  }
3173
3306
  get compressionGuidelineDraftStatePath() {
3174
- return path5.join(this.stateDir, "compression-guideline-draft-state.json");
3307
+ return path4.join(this.stateDir, "compression-guideline-draft-state.json");
3175
3308
  }
3176
3309
  get behaviorSignalsPath() {
3177
- return path5.join(this.stateDir, "behavior-signals.jsonl");
3310
+ return path4.join(this.stateDir, "behavior-signals.jsonl");
3311
+ }
3312
+ /**
3313
+ * Buffer surprise telemetry ledger (issue #563 PR 3).
3314
+ *
3315
+ * Append-only JSONL of per-turn `BUFFER_SURPRISE` events emitted by
3316
+ * `SmartBuffer` when `bufferSurpriseTriggerEnabled` is on. Each row
3317
+ * captures the score, the threshold in force at the time, whether the
3318
+ * turn caused an extract_now upgrade, and the buffer size. Kept in
3319
+ * `state/` alongside the other append-only ledgers so cleanup and
3320
+ * governance sweeps can treat it uniformly.
3321
+ */
3322
+ get bufferSurpriseLedgerPath() {
3323
+ return path4.join(this.stateDir, "buffer-surprise-ledger.jsonl");
3178
3324
  }
3179
3325
  /**
3180
3326
  * Load user-defined entity aliases from config/aliases.json in the memory store.
@@ -3182,9 +3328,9 @@ var StorageManager = class _StorageManager {
3182
3328
  * Call this once at startup (e.g. from orchestrator.initialize()).
3183
3329
  */
3184
3330
  async loadAliases() {
3185
- const aliasPath = path5.join(this.baseDir, "config", "aliases.json");
3331
+ const aliasPath = path4.join(this.baseDir, "config", "aliases.json");
3186
3332
  try {
3187
- const raw = await readFile3(aliasPath, "utf-8");
3333
+ const raw = await readFile2(aliasPath, "utf-8");
3188
3334
  const parsed = JSON.parse(raw);
3189
3335
  if (typeof parsed === "object" && parsed !== null) {
3190
3336
  userAliases = parsed;
@@ -3196,18 +3342,19 @@ var StorageManager = class _StorageManager {
3196
3342
  }
3197
3343
  async ensureDirectories() {
3198
3344
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3199
- await mkdir3(path5.join(this.factsDir, today), { recursive: true });
3200
- await mkdir3(path5.join(this.proceduresDir, today), { recursive: true });
3201
- await mkdir3(this.correctionsDir, { recursive: true });
3202
- await mkdir3(this.entitiesDir, { recursive: true });
3203
- await mkdir3(this.stateDir, { recursive: true });
3204
- await mkdir3(this.questionsDir, { recursive: true });
3205
- await mkdir3(this.artifactsDir, { recursive: true });
3206
- await mkdir3(this.identityDir, { recursive: true });
3207
- await mkdir3(this.identityIncidentsDir, { recursive: true });
3208
- await mkdir3(this.identityAuditsWeeklyDir, { recursive: true });
3209
- await mkdir3(this.identityAuditsMonthlyDir, { recursive: true });
3210
- await mkdir3(path5.join(this.baseDir, "config"), { recursive: true });
3345
+ await mkdir2(path4.join(this.factsDir, today), { recursive: true });
3346
+ await mkdir2(path4.join(this.proceduresDir, today), { recursive: true });
3347
+ await mkdir2(path4.join(this.reasoningTracesDir, today), { recursive: true });
3348
+ await mkdir2(this.correctionsDir, { recursive: true });
3349
+ await mkdir2(this.entitiesDir, { recursive: true });
3350
+ await mkdir2(this.stateDir, { recursive: true });
3351
+ await mkdir2(this.questionsDir, { recursive: true });
3352
+ await mkdir2(this.artifactsDir, { recursive: true });
3353
+ await mkdir2(this.identityDir, { recursive: true });
3354
+ await mkdir2(this.identityIncidentsDir, { recursive: true });
3355
+ await mkdir2(this.identityAuditsWeeklyDir, { recursive: true });
3356
+ await mkdir2(this.identityAuditsMonthlyDir, { recursive: true });
3357
+ await mkdir2(path4.join(this.baseDir, "config"), { recursive: true });
3211
3358
  }
3212
3359
  async writeMemory(category, content, options = {}) {
3213
3360
  await this.ensureDirectories();
@@ -3250,6 +3397,12 @@ var StorageManager = class _StorageManager {
3250
3397
  if (options.status !== void 0) {
3251
3398
  fm.status = options.status;
3252
3399
  }
3400
+ if (options.derivedFrom !== void 0 && options.derivedFrom.length > 0) {
3401
+ fm.derived_from = options.derivedFrom;
3402
+ }
3403
+ if (options.derivedVia !== void 0) {
3404
+ fm.derived_via = options.derivedVia;
3405
+ }
3253
3406
  let enrichedContent = content;
3254
3407
  if (options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
3255
3408
  enrichedContent = `${content}
@@ -3269,15 +3422,18 @@ ${sanitized.text}
3269
3422
  `;
3270
3423
  let filePath;
3271
3424
  if (category === "correction") {
3272
- filePath = path5.join(this.correctionsDir, `${id}.md`);
3425
+ filePath = path4.join(this.correctionsDir, `${id}.md`);
3273
3426
  } else if (category === "procedure") {
3274
- await mkdir3(path5.join(this.proceduresDir, today), { recursive: true });
3275
- filePath = path5.join(this.proceduresDir, today, `${id}.md`);
3427
+ await mkdir2(path4.join(this.proceduresDir, today), { recursive: true });
3428
+ filePath = path4.join(this.proceduresDir, today, `${id}.md`);
3429
+ } else if (category === "reasoning_trace") {
3430
+ await mkdir2(path4.join(this.reasoningTracesDir, today), { recursive: true });
3431
+ filePath = path4.join(this.reasoningTracesDir, today, `${id}.md`);
3276
3432
  } else {
3277
- filePath = path5.join(this.factsDir, today, `${id}.md`);
3433
+ filePath = path4.join(this.factsDir, today, `${id}.md`);
3278
3434
  }
3279
3435
  await this.snapshotBeforeWrite(filePath, "write");
3280
- await writeFile3(filePath, fileContent, "utf-8");
3436
+ await writeFile2(filePath, fileContent, "utf-8");
3281
3437
  this.invalidateAllMemoriesCache();
3282
3438
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.writeMemory", {
3283
3439
  memoryId: id,
@@ -3321,8 +3477,8 @@ ${sanitized.text}
3321
3477
  await this.ensureDirectories();
3322
3478
  const now = /* @__PURE__ */ new Date();
3323
3479
  const day = now.toISOString().slice(0, 10);
3324
- const dir = path5.join(this.artifactsDir, day);
3325
- await mkdir3(dir, { recursive: true });
3480
+ const dir = path4.join(this.artifactsDir, day);
3481
+ await mkdir2(dir, { recursive: true });
3326
3482
  const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
3327
3483
  const fm = {
3328
3484
  id,
@@ -3345,8 +3501,8 @@ ${sanitized.text}
3345
3501
  log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
3346
3502
  return "";
3347
3503
  }
3348
- const filePath = path5.join(dir, `${id}.md`);
3349
- await writeFile3(filePath, `${serializeFrontmatter(fm)}
3504
+ const filePath = path4.join(dir, `${id}.md`);
3505
+ await writeFile2(filePath, `${serializeFrontmatter(fm)}
3350
3506
 
3351
3507
  ${sanitized.text}
3352
3508
  `, "utf-8");
@@ -3373,7 +3529,7 @@ ${sanitized.text}
3373
3529
  try {
3374
3530
  const entries = await readdir(dir, { withFileTypes: true });
3375
3531
  for (const entry of entries) {
3376
- const fullPath = path5.join(dir, entry.name);
3532
+ const fullPath = path4.join(dir, entry.name);
3377
3533
  if (entry.isDirectory()) {
3378
3534
  await readDir(fullPath);
3379
3535
  continue;
@@ -3439,7 +3595,7 @@ ${sanitized.text}
3439
3595
  log.debug(`fuzzy match: "${normalized}" \u2192 existing "${match}"`);
3440
3596
  normalized = match;
3441
3597
  }
3442
- const filePath = path5.join(this.entitiesDir, `${normalized}.md`);
3598
+ const filePath = path4.join(this.entitiesDir, `${normalized}.md`);
3443
3599
  let entity = {
3444
3600
  name,
3445
3601
  type,
@@ -3458,7 +3614,7 @@ ${sanitized.text}
3458
3614
  aliases: []
3459
3615
  };
3460
3616
  try {
3461
- const existing = await readFile3(filePath, "utf-8");
3617
+ const existing = await readFile2(filePath, "utf-8");
3462
3618
  entity = parseEntityFile(existing, this.entitySchemas);
3463
3619
  } catch {
3464
3620
  }
@@ -3516,7 +3672,7 @@ ${sanitized.text}
3516
3672
  entity.created = entity.created || timestamp;
3517
3673
  entity.updated = (/* @__PURE__ */ new Date()).toISOString();
3518
3674
  await this.snapshotBeforeWrite(filePath, "write");
3519
- await writeFile3(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
3675
+ await writeFile2(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
3520
3676
  this.invalidateKnowledgeIndexCache();
3521
3677
  this.bumpMemoryStatusVersion();
3522
3678
  log.debug(`wrote entity ${normalized}`);
@@ -3524,7 +3680,7 @@ ${sanitized.text}
3524
3680
  }
3525
3681
  async readProfile() {
3526
3682
  try {
3527
- return await readFile3(this.profilePath, "utf-8");
3683
+ return await readFile2(this.profilePath, "utf-8");
3528
3684
  } catch {
3529
3685
  return "";
3530
3686
  }
@@ -3532,7 +3688,7 @@ ${sanitized.text}
3532
3688
  async writeProfile(content) {
3533
3689
  await this.ensureDirectories();
3534
3690
  await this.snapshotBeforeWrite(this.profilePath, "consolidation");
3535
- await writeFile3(this.profilePath, content, "utf-8");
3691
+ await writeFile2(this.profilePath, content, "utf-8");
3536
3692
  log.debug("updated profile.md");
3537
3693
  }
3538
3694
  /**
@@ -3650,7 +3806,7 @@ ${sanitized.text}
3650
3806
  * per-process in-memory cache safe across process boundaries.
3651
3807
  */
3652
3808
  invalidateColdMemoriesCache() {
3653
- const coldRoot = path5.join(this.baseDir, "cold");
3809
+ const coldRoot = path4.join(this.baseDir, "cold");
3654
3810
  _StorageManager.coldMemoriesCache.delete(coldRoot);
3655
3811
  this.bumpColdWriteVersion();
3656
3812
  }
@@ -3678,7 +3834,7 @@ ${sanitized.text}
3678
3834
  const entries = await readdir(dir, { withFileTypes: true });
3679
3835
  const subdirs = [];
3680
3836
  for (const entry of entries) {
3681
- const fullPath = path5.join(dir, entry.name);
3837
+ const fullPath = path4.join(dir, entry.name);
3682
3838
  if (entry.isDirectory()) {
3683
3839
  subdirs.push(fullPath);
3684
3840
  } else if (entry.name.endsWith(".md")) {
@@ -3693,6 +3849,7 @@ ${sanitized.text}
3693
3849
  };
3694
3850
  await collectPaths(this.factsDir);
3695
3851
  await collectPaths(this.proceduresDir);
3852
+ await collectPaths(this.reasoningTracesDir);
3696
3853
  await collectPaths(this.correctionsDir);
3697
3854
  return filePaths;
3698
3855
  }
@@ -3705,7 +3862,7 @@ ${sanitized.text}
3705
3862
  const results = await Promise.all(
3706
3863
  batch.map(async (fullPath) => {
3707
3864
  try {
3708
- const raw = await readFile3(fullPath, "utf-8");
3865
+ const raw = await readFile2(fullPath, "utf-8");
3709
3866
  const parsed = parseFrontmatter2(raw);
3710
3867
  if (!parsed) return null;
3711
3868
  return {
@@ -3730,7 +3887,7 @@ ${sanitized.text}
3730
3887
  }
3731
3888
  async readWindowUpdatedMs(filePath) {
3732
3889
  try {
3733
- const raw = await readFile3(filePath, "utf-8");
3890
+ const raw = await readFile2(filePath, "utf-8");
3734
3891
  const match = raw.match(/^---\n([\s\S]*?)\n---\n?/);
3735
3892
  if (!match) return null;
3736
3893
  const frontmatterBlock = match[1];
@@ -3760,7 +3917,7 @@ ${sanitized.text}
3760
3917
  const correctionPaths = [];
3761
3918
  const factPaths = [];
3762
3919
  for (const filePath of filePaths) {
3763
- if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path5.sep}`)) {
3920
+ if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path4.sep}`)) {
3764
3921
  correctionPaths.push(filePath);
3765
3922
  } else {
3766
3923
  factPaths.push(filePath);
@@ -3880,7 +4037,7 @@ ${sanitized.text}
3880
4037
  const entries = await readdir(dir, { withFileTypes: true });
3881
4038
  const subdirs = [];
3882
4039
  for (const entry of entries) {
3883
- const fullPath = path5.join(dir, entry.name);
4040
+ const fullPath = path4.join(dir, entry.name);
3884
4041
  if (entry.isDirectory()) {
3885
4042
  subdirs.push(fullPath);
3886
4043
  } else if (entry.name.endsWith(".md")) {
@@ -3909,12 +4066,12 @@ ${sanitized.text}
3909
4066
  try {
3910
4067
  const entries = await readdir(dir, { withFileTypes: true });
3911
4068
  for (const entry of entries) {
3912
- const fullPath = path5.join(dir, entry.name);
4069
+ const fullPath = path4.join(dir, entry.name);
3913
4070
  if (entry.isDirectory()) {
3914
4071
  await readDir(fullPath);
3915
4072
  } else if (entry.name.endsWith(".md")) {
3916
4073
  try {
3917
- const raw = await readFile3(fullPath, "utf-8");
4074
+ const raw = await readFile2(fullPath, "utf-8");
3918
4075
  const parsed = parseFrontmatter2(raw);
3919
4076
  if (parsed) {
3920
4077
  memories.push({
@@ -3940,7 +4097,7 @@ ${sanitized.text}
3940
4097
  /** Read a single memory file by its absolute path. Returns null if unreadable. */
3941
4098
  async readMemoryByPath(filePath) {
3942
4099
  try {
3943
- const raw = await readFile3(filePath, "utf-8");
4100
+ const raw = await readFile2(filePath, "utf-8");
3944
4101
  const parsed = parseFrontmatter2(raw);
3945
4102
  if (parsed) {
3946
4103
  return {
@@ -3953,11 +4110,11 @@ ${sanitized.text}
3953
4110
  content: parsed.content
3954
4111
  };
3955
4112
  }
3956
- const normalizedPath = filePath.split(path5.sep).join("/");
4113
+ const normalizedPath = filePath.split(path4.sep).join("/");
3957
4114
  if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
3958
4115
  const entity = parseEntityFile(raw, this.entitySchemas);
3959
4116
  if (!entity.name) return null;
3960
- const nameWithoutExt = path5.basename(filePath, ".md");
4117
+ const nameWithoutExt = path4.basename(filePath, ".md");
3961
4118
  const fileMtime = entity.updated || await stat2(filePath).then((s) => s.mtime.toISOString()).catch(() => (/* @__PURE__ */ new Date(0)).toISOString());
3962
4119
  return {
3963
4120
  path: filePath,
@@ -3980,7 +4137,7 @@ ${sanitized.text}
3980
4137
  }
3981
4138
  }
3982
4139
  resolveTierRootDir(tier) {
3983
- return tier === "cold" ? path5.join(this.baseDir, "cold") : this.baseDir;
4140
+ return tier === "cold" ? path4.join(this.baseDir, "cold") : this.baseDir;
3984
4141
  }
3985
4142
  resolveMemoryDateDir(memory) {
3986
4143
  const preferred = memory.frontmatter.created || memory.frontmatter.updated;
@@ -3995,30 +4152,33 @@ ${sanitized.text}
3995
4152
  buildTierMemoryPath(memory, tier) {
3996
4153
  const root = this.resolveTierRootDir(tier);
3997
4154
  if (this.isArtifactMemory(memory)) {
3998
- return path5.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4155
+ return path4.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
3999
4156
  }
4000
4157
  if (memory.frontmatter.category === "correction") {
4001
- return path5.join(root, "corrections", `${memory.frontmatter.id}.md`);
4158
+ return path4.join(root, "corrections", `${memory.frontmatter.id}.md`);
4002
4159
  }
4003
4160
  if (memory.frontmatter.category === "procedure") {
4004
- return path5.join(root, "procedures", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4161
+ return path4.join(root, "procedures", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4162
+ }
4163
+ if (memory.frontmatter.category === "reasoning_trace") {
4164
+ return path4.join(root, "reasoning-traces", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4005
4165
  }
4006
- return path5.join(root, "facts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4166
+ return path4.join(root, "facts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4007
4167
  }
4008
4168
  async writeMemoryFileAtomic(targetPath, memory) {
4009
4169
  const fileContent = `${serializeFrontmatter(memory.frontmatter)}
4010
4170
 
4011
4171
  ${memory.content}
4012
4172
  `;
4013
- await mkdir3(path5.dirname(targetPath), { recursive: true });
4173
+ await mkdir2(path4.dirname(targetPath), { recursive: true });
4014
4174
  const tempPath = `${targetPath}.tmp-${process.pid}-${Date.now()}`;
4015
4175
  try {
4016
- await writeFile3(tempPath, fileContent, "utf-8");
4176
+ await writeFile2(tempPath, fileContent, "utf-8");
4017
4177
  await rename(tempPath, targetPath);
4018
4178
  this.invalidateAllMemoriesCache();
4019
4179
  } catch (err) {
4020
4180
  try {
4021
- await unlink2(tempPath);
4181
+ await unlink(tempPath);
4022
4182
  } catch {
4023
4183
  }
4024
4184
  throw err;
@@ -4026,11 +4186,11 @@ ${memory.content}
4026
4186
  }
4027
4187
  async moveMemoryToPath(memory, targetPath) {
4028
4188
  await this.writeMemoryFileAtomic(targetPath, memory);
4029
- const sourcePath = path5.resolve(memory.path);
4030
- const destPath = path5.resolve(targetPath);
4189
+ const sourcePath = path4.resolve(memory.path);
4190
+ const destPath = path4.resolve(targetPath);
4031
4191
  if (sourcePath !== destPath) {
4032
4192
  try {
4033
- await unlink2(memory.path);
4193
+ await unlink(memory.path);
4034
4194
  } catch (err) {
4035
4195
  const message = err instanceof Error ? err.message : String(err);
4036
4196
  if (!message.includes("ENOENT")) {
@@ -4042,15 +4202,15 @@ ${memory.content}
4042
4202
  }
4043
4203
  async migrateMemoryToTier(memory, targetTier) {
4044
4204
  const targetPath = this.buildTierMemoryPath(memory, targetTier);
4045
- const sourcePath = path5.resolve(memory.path);
4046
- const destPath = path5.resolve(targetPath);
4205
+ const sourcePath = path4.resolve(memory.path);
4206
+ const destPath = path4.resolve(targetPath);
4047
4207
  if (sourcePath === destPath) {
4048
4208
  return { changed: false, targetPath };
4049
4209
  }
4050
4210
  const existing = await this.readMemoryByPath(targetPath);
4051
4211
  if (existing?.frontmatter.id === memory.frontmatter.id) {
4052
4212
  try {
4053
- await unlink2(memory.path);
4213
+ await unlink(memory.path);
4054
4214
  } catch (err) {
4055
4215
  const message = err instanceof Error ? err.message : String(err);
4056
4216
  if (!message.includes("ENOENT")) {
@@ -4069,7 +4229,7 @@ ${memory.content}
4069
4229
  return { changed: true, targetPath };
4070
4230
  }
4071
4231
  get archiveDir() {
4072
- return path5.join(this.baseDir, "archive");
4232
+ return path4.join(this.baseDir, "archive");
4073
4233
  }
4074
4234
  /**
4075
4235
  * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
@@ -4080,8 +4240,8 @@ ${memory.content}
4080
4240
  try {
4081
4241
  const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
4082
4242
  const today = now.toISOString().slice(0, 10);
4083
- const destDir = path5.join(this.archiveDir, today);
4084
- await mkdir3(destDir, { recursive: true });
4243
+ const destDir = path4.join(this.archiveDir, today);
4244
+ await mkdir2(destDir, { recursive: true });
4085
4245
  const updatedFm = {
4086
4246
  ...memory.frontmatter,
4087
4247
  status: "archived",
@@ -4092,9 +4252,9 @@ ${memory.content}
4092
4252
 
4093
4253
  ${memory.content}
4094
4254
  `;
4095
- const destPath = path5.join(destDir, path5.basename(memory.path));
4096
- await writeFile3(destPath, fileContent, "utf-8");
4097
- await unlink2(memory.path);
4255
+ const destPath = path4.join(destDir, path4.basename(memory.path));
4256
+ await writeFile2(destPath, fileContent, "utf-8");
4257
+ await unlink(memory.path);
4098
4258
  this.invalidateAllMemoriesCache();
4099
4259
  await this.appendGeneratedMemoryLifecycleEventFailOpen(
4100
4260
  "storage.archiveMemory",
@@ -4129,7 +4289,7 @@ ${memory.content}
4129
4289
  }
4130
4290
  async readEntity(name) {
4131
4291
  try {
4132
- return await readFile3(path5.join(this.entitiesDir, `${name}.md`), "utf-8");
4292
+ return await readFile2(path4.join(this.entitiesDir, `${name}.md`), "utf-8");
4133
4293
  } catch {
4134
4294
  return "";
4135
4295
  }
@@ -4183,7 +4343,7 @@ ${memory.content}
4183
4343
  const memory = memories.find((m) => m.frontmatter.id === id);
4184
4344
  if (!memory) return false;
4185
4345
  try {
4186
- await unlink2(memory.path);
4346
+ await unlink(memory.path);
4187
4347
  this.invalidateAllMemoriesCache();
4188
4348
  this.bumpMemoryStatusVersion();
4189
4349
  log.debug(`invalidated memory ${id}`);
@@ -4214,7 +4374,7 @@ ${memory.content}
4214
4374
 
4215
4375
  ${sanitized.text}
4216
4376
  `;
4217
- await writeFile3(memory.path, fileContent, "utf-8");
4377
+ await writeFile2(memory.path, fileContent, "utf-8");
4218
4378
  this.invalidateAllMemoriesCache();
4219
4379
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.updateMemory", {
4220
4380
  memoryId: id,
@@ -4246,9 +4406,9 @@ ${sanitized.text}
4246
4406
 
4247
4407
  ${memory.content}
4248
4408
  `;
4249
- await writeFile3(memory.path, fileContent, "utf-8");
4409
+ await writeFile2(memory.path, fileContent, "utf-8");
4250
4410
  this.invalidateAllMemoriesCache();
4251
- if (memory.path.includes(`${path5.sep}cold${path5.sep}`)) {
4411
+ if (memory.path.includes(`${path4.sep}cold${path4.sep}`)) {
4252
4412
  this.invalidateColdMemoriesCache();
4253
4413
  }
4254
4414
  await this.appendGeneratedMemoryLifecycleEventFailOpen(
@@ -4295,7 +4455,7 @@ ${memory.content}
4295
4455
  const expiresAt = new Date(m.frontmatter.expiresAt).getTime();
4296
4456
  if (expiresAt < now) {
4297
4457
  try {
4298
- await unlink2(m.path);
4458
+ await unlink(m.path);
4299
4459
  deleted.push(m);
4300
4460
  log.debug(`cleaned expired memory ${m.frontmatter.id} (TTL expired)`);
4301
4461
  } catch {
@@ -4309,9 +4469,9 @@ ${memory.content}
4309
4469
  return deleted;
4310
4470
  }
4311
4471
  async loadBuffer() {
4312
- const bufferPath = path5.join(this.stateDir, "buffer.json");
4472
+ const bufferPath = path4.join(this.stateDir, "buffer.json");
4313
4473
  try {
4314
- const raw = await readFile3(bufferPath, "utf-8");
4474
+ const raw = await readFile2(bufferPath, "utf-8");
4315
4475
  return JSON.parse(raw);
4316
4476
  } catch {
4317
4477
  return { turns: [], lastExtractionAt: null, extractionCount: 0 };
@@ -4319,13 +4479,13 @@ ${memory.content}
4319
4479
  }
4320
4480
  async saveBuffer(state) {
4321
4481
  await this.ensureDirectories();
4322
- const bufferPath = path5.join(this.stateDir, "buffer.json");
4323
- await writeFile3(bufferPath, JSON.stringify(state, null, 2), "utf-8");
4482
+ const bufferPath = path4.join(this.stateDir, "buffer.json");
4483
+ await writeFile2(bufferPath, JSON.stringify(state, null, 2), "utf-8");
4324
4484
  }
4325
4485
  async loadMeta() {
4326
- const metaPath = path5.join(this.stateDir, "meta.json");
4486
+ const metaPath = path4.join(this.stateDir, "meta.json");
4327
4487
  try {
4328
- const raw = await readFile3(metaPath, "utf-8");
4488
+ const raw = await readFile2(metaPath, "utf-8");
4329
4489
  const parsed = JSON.parse(raw);
4330
4490
  return {
4331
4491
  extractionCount: typeof parsed.extractionCount === "number" ? parsed.extractionCount : 0,
@@ -4355,8 +4515,8 @@ ${memory.content}
4355
4515
  }
4356
4516
  async saveMeta(state) {
4357
4517
  await this.ensureDirectories();
4358
- const metaPath = path5.join(this.stateDir, "meta.json");
4359
- await writeFile3(metaPath, JSON.stringify(state, null, 2), "utf-8");
4518
+ const metaPath = path4.join(this.stateDir, "meta.json");
4519
+ await writeFile2(metaPath, JSON.stringify(state, null, 2), "utf-8");
4360
4520
  }
4361
4521
  async appendMemoryActionEvents(events) {
4362
4522
  if (events.length === 0) return 0;
@@ -4388,12 +4548,102 @@ ${memory.content}
4388
4548
  await appendFile(this.memoryLifecycleLedgerPath, payload, "utf-8");
4389
4549
  return events.length;
4390
4550
  }
4551
+ /**
4552
+ * Append a batch of `BUFFER_SURPRISE` telemetry events (issue #563 PR 3).
4553
+ *
4554
+ * Each event records a single buffer flush decision driven by the
4555
+ * surprise gate. The ledger is consumed by
4556
+ * `reportBufferSurpriseDistribution` (Doctor report) and by downstream
4557
+ * benchmark analysis. This method is fire-and-forget by contract:
4558
+ * callers log but do not fail the hot path if the append throws.
4559
+ */
4560
+ async appendBufferSurpriseEvents(events) {
4561
+ if (events.length === 0) return 0;
4562
+ await this.ensureDirectories();
4563
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4564
+ const payload = events.map((event) => {
4565
+ const normalized = {
4566
+ ...event,
4567
+ event: "BUFFER_SURPRISE",
4568
+ timestamp: event.timestamp && event.timestamp.length > 0 ? event.timestamp : nowIso
4569
+ };
4570
+ return `${JSON.stringify(normalized)}
4571
+ `;
4572
+ }).join("");
4573
+ await appendFile(this.bufferSurpriseLedgerPath, payload, "utf-8");
4574
+ return events.length;
4575
+ }
4576
+ /**
4577
+ * Read the buffer-surprise ledger, most recent rows last.
4578
+ *
4579
+ * `limit` bounds the number of **valid rows** returned (not the
4580
+ * number of raw lines parsed). We parse every row, discard malformed
4581
+ * ones, then take the tail — so a partial/truncated trailing line
4582
+ * (the common failure mode after an interrupted append) cannot hide
4583
+ * otherwise-valid recent data above it.
4584
+ *
4585
+ * Non-positive / non-integer / non-finite limits return `[]` rather
4586
+ * than the entire file, matching the other ledger readers in this
4587
+ * class and protecting against `slice(-0.5)` → `slice(-0)` silently
4588
+ * devolving into an unbounded parse.
4589
+ *
4590
+ * # Performance note
4591
+ *
4592
+ * For very large ledgers (issue #563 follow-up), a tail-first reader
4593
+ * would avoid parsing the full file when only a recent window is
4594
+ * needed. We keep the full-scan implementation here because:
4595
+ *
4596
+ * - the ledger is opt-in (flag off by default), so early deployments
4597
+ * accumulate rows slowly;
4598
+ * - telemetry rows are small (~200 bytes), so even 100k rows parse
4599
+ * in well under a second;
4600
+ * - the governance archive/cleanup flow can trim the ledger when
4601
+ * size becomes a concern, reusing the existing maintenance hooks.
4602
+ *
4603
+ * Swap to a chunked tail-reader if production logs show this is a
4604
+ * hot path — leaving that work for a follow-up keeps this PR scoped
4605
+ * to correctness, not optimization.
4606
+ */
4607
+ async readBufferSurpriseEvents(options = {}) {
4608
+ let raw;
4609
+ try {
4610
+ raw = await readFile2(this.bufferSurpriseLedgerPath, "utf-8");
4611
+ } catch (err) {
4612
+ const code = err.code;
4613
+ if (code === "ENOENT") return [];
4614
+ throw err;
4615
+ }
4616
+ let effectiveLimit = null;
4617
+ if (options.limit !== void 0) {
4618
+ if (typeof options.limit !== "number" || !Number.isFinite(options.limit) || options.limit <= 0) {
4619
+ return [];
4620
+ }
4621
+ const floored = Math.floor(options.limit);
4622
+ if (floored <= 0) return [];
4623
+ effectiveLimit = floored;
4624
+ }
4625
+ const lines = raw.split("\n");
4626
+ const events = [];
4627
+ for (const line of lines) {
4628
+ const trimmed = line.trim();
4629
+ if (trimmed.length === 0) continue;
4630
+ try {
4631
+ const parsed = JSON.parse(trimmed);
4632
+ if (isValidBufferSurpriseEvent(parsed)) {
4633
+ events.push(parsed);
4634
+ }
4635
+ } catch {
4636
+ }
4637
+ }
4638
+ if (effectiveLimit === null) return events;
4639
+ return events.slice(-effectiveLimit);
4640
+ }
4391
4641
  async appendBehaviorSignals(events) {
4392
4642
  if (events.length === 0) return 0;
4393
4643
  await this.ensureDirectories();
4394
4644
  let existingKeys = /* @__PURE__ */ new Set();
4395
4645
  try {
4396
- const raw = await readFile3(this.behaviorSignalsPath, "utf-8");
4646
+ const raw = await readFile2(this.behaviorSignalsPath, "utf-8");
4397
4647
  const lines = raw.split("\n");
4398
4648
  for (const line of lines) {
4399
4649
  const row = line.trim();
@@ -4429,7 +4679,7 @@ ${memory.content}
4429
4679
  async appendReextractJobs(events) {
4430
4680
  if (events.length === 0) return 0;
4431
4681
  await this.ensureDirectories();
4432
- const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
4682
+ const filePath = path4.join(this.stateDir, "reextract-jobs.jsonl");
4433
4683
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
4434
4684
  try {
4435
4685
  await appendFile(filePath, lines, "utf-8");
@@ -4440,9 +4690,9 @@ ${memory.content}
4440
4690
  }
4441
4691
  async readReextractJobs(limit = 200) {
4442
4692
  const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
4443
- const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
4693
+ const filePath = path4.join(this.stateDir, "reextract-jobs.jsonl");
4444
4694
  try {
4445
- const raw = await readFile3(filePath, "utf-8");
4695
+ const raw = await readFile2(filePath, "utf-8");
4446
4696
  const lines = raw.split("\n").filter((line) => line.trim().length > 0);
4447
4697
  const parsed = [];
4448
4698
  for (const line of lines) {
@@ -4470,7 +4720,7 @@ ${memory.content}
4470
4720
  const cappedLimit = Math.max(0, Math.floor(limit));
4471
4721
  if (cappedLimit === 0) return [];
4472
4722
  try {
4473
- const raw = await readFile3(this.behaviorSignalsPath, "utf-8");
4723
+ const raw = await readFile2(this.behaviorSignalsPath, "utf-8");
4474
4724
  const out = [];
4475
4725
  const lines = raw.split("\n");
4476
4726
  for (let i = lines.length - 1; i >= 0 && out.length < cappedLimit; i -= 1) {
@@ -4493,7 +4743,7 @@ ${memory.content}
4493
4743
  const cappedLimit = Math.max(0, Math.floor(limit));
4494
4744
  if (cappedLimit === 0) return [];
4495
4745
  try {
4496
- const raw = await readFile3(this.memoryActionsPath, "utf-8");
4746
+ const raw = await readFile2(this.memoryActionsPath, "utf-8");
4497
4747
  const out = [];
4498
4748
  const lines = raw.split("\n");
4499
4749
  for (let i = lines.length - 1; i >= 0 && out.length < cappedLimit; i -= 1) {
@@ -4514,7 +4764,7 @@ ${memory.content}
4514
4764
  }
4515
4765
  async readAllMemoryLifecycleEvents() {
4516
4766
  try {
4517
- const raw = await readFile3(this.memoryLifecycleLedgerPath, "utf-8");
4767
+ const raw = await readFile2(this.memoryLifecycleLedgerPath, "utf-8");
4518
4768
  const out = [];
4519
4769
  const lines = raw.split("\n");
4520
4770
  for (const line of lines) {
@@ -4541,34 +4791,34 @@ ${memory.content}
4541
4791
  }
4542
4792
  async writeCompressionGuidelines(content) {
4543
4793
  await this.ensureDirectories();
4544
- await writeFile3(this.compressionGuidelinesPath, content, "utf-8");
4794
+ await writeFile2(this.compressionGuidelinesPath, content, "utf-8");
4545
4795
  }
4546
4796
  async readCompressionGuidelines() {
4547
4797
  try {
4548
- return await readFile3(this.compressionGuidelinesPath, "utf-8");
4798
+ return await readFile2(this.compressionGuidelinesPath, "utf-8");
4549
4799
  } catch {
4550
4800
  return null;
4551
4801
  }
4552
4802
  }
4553
4803
  async writeCompressionGuidelineDraft(content) {
4554
4804
  await this.ensureDirectories();
4555
- await writeFile3(this.compressionGuidelineDraftPath, content, "utf-8");
4805
+ await writeFile2(this.compressionGuidelineDraftPath, content, "utf-8");
4556
4806
  }
4557
4807
  async readCompressionGuidelineDraft() {
4558
4808
  try {
4559
- return await readFile3(this.compressionGuidelineDraftPath, "utf-8");
4809
+ return await readFile2(this.compressionGuidelineDraftPath, "utf-8");
4560
4810
  } catch {
4561
4811
  return null;
4562
4812
  }
4563
4813
  }
4564
4814
  async writeCompressionGuidelineOptimizerState(state) {
4565
4815
  await this.ensureDirectories();
4566
- await writeFile3(this.compressionGuidelineStatePath, `${JSON.stringify(state, null, 2)}
4816
+ await writeFile2(this.compressionGuidelineStatePath, `${JSON.stringify(state, null, 2)}
4567
4817
  `, "utf-8");
4568
4818
  }
4569
4819
  async writeCompressionGuidelineDraftState(state) {
4570
4820
  await this.ensureDirectories();
4571
- await writeFile3(this.compressionGuidelineDraftStatePath, `${JSON.stringify(state, null, 2)}
4821
+ await writeFile2(this.compressionGuidelineDraftStatePath, `${JSON.stringify(state, null, 2)}
4572
4822
  `, "utf-8");
4573
4823
  }
4574
4824
  async readCompressionGuidelineOptimizerState() {
@@ -4590,8 +4840,8 @@ ${memory.content}
4590
4840
  return false;
4591
4841
  }
4592
4842
  if (draftState.contentHash) {
4593
- const contentHash2 = createHash2("sha256").update(draftContent).digest("hex");
4594
- if (contentHash2 !== draftState.contentHash) return false;
4843
+ const contentHash = createHash("sha256").update(draftContent).digest("hex");
4844
+ if (contentHash !== draftState.contentHash) return false;
4595
4845
  }
4596
4846
  await this.writeCompressionGuidelines(draftContent);
4597
4847
  await this.writeCompressionGuidelineOptimizerState({
@@ -4599,8 +4849,8 @@ ${memory.content}
4599
4849
  activationState: "active"
4600
4850
  });
4601
4851
  await Promise.all([
4602
- unlink2(this.compressionGuidelineDraftPath).catch(() => void 0),
4603
- unlink2(this.compressionGuidelineDraftStatePath).catch(() => void 0)
4852
+ unlink(this.compressionGuidelineDraftPath).catch(() => void 0),
4853
+ unlink(this.compressionGuidelineDraftStatePath).catch(() => void 0)
4604
4854
  ]);
4605
4855
  return true;
4606
4856
  }
@@ -4617,12 +4867,12 @@ ${memory.content}
4617
4867
  return typeof rule.action === "string" && typeof rule.delta === "number" && Number.isFinite(rule.delta) && (rule.direction === "increase" || rule.direction === "decrease" || rule.direction === "hold") && (rule.confidence === "low" || rule.confidence === "medium" || rule.confidence === "high") && Array.isArray(rule.notes) && rule.notes.every((note) => typeof note === "string");
4618
4868
  };
4619
4869
  try {
4620
- const raw = await readFile3(filePath, "utf-8");
4870
+ const raw = await readFile2(filePath, "utf-8");
4621
4871
  const parsed = JSON.parse(raw);
4622
4872
  const sourceWindow = parsed?.sourceWindow;
4623
4873
  const eventCounts = parsed?.eventCounts;
4624
4874
  const activationState = parsed?.activationState === "draft" || parsed?.activationState === "active" ? parsed.activationState : void 0;
4625
- const contentHash2 = typeof parsed?.contentHash === "string" && parsed.contentHash.length > 0 ? parsed.contentHash : void 0;
4875
+ const contentHash = typeof parsed?.contentHash === "string" && parsed.contentHash.length > 0 ? parsed.contentHash : void 0;
4626
4876
  const actionSummaries = Array.isArray(parsed?.actionSummaries) ? parsed.actionSummaries.filter(isValidActionSummary) : void 0;
4627
4877
  const ruleUpdates = Array.isArray(parsed?.ruleUpdates) ? parsed.ruleUpdates.filter(isValidRuleUpdate) : void 0;
4628
4878
  if (!isFiniteNonNegativeInteger(parsed?.version) || typeof parsed?.updatedAt !== "string" || parsed.updatedAt.length === 0 || !sourceWindow || typeof sourceWindow.from !== "string" || sourceWindow.from.length === 0 || typeof sourceWindow.to !== "string" || sourceWindow.to.length === 0 || !eventCounts || !isFiniteNonNegativeInteger(eventCounts.total) || !isFiniteNonNegativeInteger(eventCounts.applied) || !isFiniteNonNegativeInteger(eventCounts.skipped) || !isFiniteNonNegativeInteger(eventCounts.failed) || !isFiniteNonNegativeInteger(parsed?.guidelineVersion)) {
@@ -4642,7 +4892,7 @@ ${memory.content}
4642
4892
  failed: eventCounts.failed
4643
4893
  },
4644
4894
  guidelineVersion: parsed.guidelineVersion,
4645
- ...contentHash2 ? { contentHash: contentHash2 } : {},
4895
+ ...contentHash ? { contentHash } : {},
4646
4896
  ...activationState ? { activationState } : {},
4647
4897
  ...actionSummaries ? { actionSummaries } : {},
4648
4898
  ...ruleUpdates ? { ruleUpdates } : {}
@@ -4653,11 +4903,11 @@ ${memory.content}
4653
4903
  }
4654
4904
  async writeIdentityAnchor(content) {
4655
4905
  await this.ensureDirectories();
4656
- await writeFile3(this.identityAnchorPath, content, "utf-8");
4906
+ await writeFile2(this.identityAnchorPath, content, "utf-8");
4657
4907
  }
4658
4908
  async readIdentityAnchor() {
4659
4909
  try {
4660
- return await readFile3(this.identityAnchorPath, "utf-8");
4910
+ return await readFile2(this.identityAnchorPath, "utf-8");
4661
4911
  } catch {
4662
4912
  return null;
4663
4913
  }
@@ -4669,8 +4919,8 @@ ${memory.content}
4669
4919
  const date = nowIso.slice(0, 10);
4670
4920
  const id = this.generateId("incident");
4671
4921
  const incident = createContinuityIncidentRecord(id, input, nowIso);
4672
- const filePath = path5.join(this.identityIncidentsDir, `${date}-${id}.md`);
4673
- await writeFile3(filePath, serializeContinuityIncident(incident), "utf-8");
4922
+ const filePath = path4.join(this.identityIncidentsDir, `${date}-${id}.md`);
4923
+ await writeFile2(filePath, serializeContinuityIncident(incident), "utf-8");
4674
4924
  return { ...incident, filePath };
4675
4925
  }
4676
4926
  async readContinuityIncidents(limit = 200, state = "all") {
@@ -4682,9 +4932,9 @@ ${memory.content}
4682
4932
  const incidents = [];
4683
4933
  for (const file of candidates) {
4684
4934
  if (incidents.length >= cappedLimit) break;
4685
- const filePath = path5.join(this.identityIncidentsDir, file);
4935
+ const filePath = path4.join(this.identityIncidentsDir, file);
4686
4936
  try {
4687
- const raw = await readFile3(filePath, "utf-8");
4937
+ const raw = await readFile2(filePath, "utf-8");
4688
4938
  const parsed = parseContinuityIncident(raw);
4689
4939
  if (!parsed) continue;
4690
4940
  if (state !== "all" && parsed.state !== state) continue;
@@ -4703,33 +4953,33 @@ ${memory.content}
4703
4953
  if (!target || !directFilePath) return null;
4704
4954
  if (target.state === "closed") return target;
4705
4955
  const closed = closeContinuityIncidentRecord(target, closure, (/* @__PURE__ */ new Date()).toISOString());
4706
- await writeFile3(directFilePath, serializeContinuityIncident(closed), "utf-8");
4956
+ await writeFile2(directFilePath, serializeContinuityIncident(closed), "utf-8");
4707
4957
  return { ...closed, filePath: directFilePath };
4708
4958
  }
4709
4959
  async writeIdentityAudit(period, key, content) {
4710
4960
  await this.ensureDirectories();
4711
4961
  const safeKey = this.sanitizeIdentityAuditKey(key);
4712
4962
  const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
4713
- const filePath = path5.join(dir, `${safeKey}.md`);
4714
- await writeFile3(filePath, content, "utf-8");
4963
+ const filePath = path4.join(dir, `${safeKey}.md`);
4964
+ await writeFile2(filePath, content, "utf-8");
4715
4965
  return filePath;
4716
4966
  }
4717
4967
  async readIdentityAudit(period, key) {
4718
4968
  try {
4719
4969
  const safeKey = this.sanitizeIdentityAuditKey(key);
4720
4970
  const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
4721
- return await readFile3(path5.join(dir, `${safeKey}.md`), "utf-8");
4971
+ return await readFile2(path4.join(dir, `${safeKey}.md`), "utf-8");
4722
4972
  } catch {
4723
4973
  return null;
4724
4974
  }
4725
4975
  }
4726
4976
  async writeIdentityImprovementLoops(content) {
4727
4977
  await this.ensureDirectories();
4728
- await writeFile3(this.identityImprovementLoopsPath, content, "utf-8");
4978
+ await writeFile2(this.identityImprovementLoopsPath, content, "utf-8");
4729
4979
  }
4730
4980
  async readIdentityImprovementLoops() {
4731
4981
  try {
4732
- return await readFile3(this.identityImprovementLoopsPath, "utf-8");
4982
+ return await readFile2(this.identityImprovementLoopsPath, "utf-8");
4733
4983
  } catch {
4734
4984
  return null;
4735
4985
  }
@@ -4767,7 +5017,7 @@ ${memory.content}
4767
5017
  }
4768
5018
  async readContinuityIncidentFile(filePath) {
4769
5019
  try {
4770
- const raw = await readFile3(filePath, "utf-8");
5020
+ const raw = await readFile2(filePath, "utf-8");
4771
5021
  const parsed = parseContinuityIncident(raw);
4772
5022
  return parsed ? { ...parsed, filePath } : null;
4773
5023
  } catch {
@@ -4778,12 +5028,12 @@ ${memory.content}
4778
5028
  const fileNames = await this.readContinuityIncidentFileNames();
4779
5029
  const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
4780
5030
  if (directMatch) {
4781
- const directPath = path5.join(this.identityIncidentsDir, directMatch);
5031
+ const directPath = path4.join(this.identityIncidentsDir, directMatch);
4782
5032
  const parsed = await this.readContinuityIncidentFile(directPath);
4783
5033
  if (parsed?.id === id) return directPath;
4784
5034
  }
4785
5035
  for (const fileName of fileNames) {
4786
- const filePath = path5.join(this.identityIncidentsDir, fileName);
5036
+ const filePath = path4.join(this.identityIncidentsDir, fileName);
4787
5037
  const parsed = await this.readContinuityIncidentFile(filePath);
4788
5038
  if (parsed?.id === id) return filePath;
4789
5039
  }
@@ -4797,7 +5047,7 @@ ${memory.content}
4797
5047
  return trimmed;
4798
5048
  }
4799
5049
  async writeQuestion(question, context, priority) {
4800
- await mkdir3(this.questionsDir, { recursive: true });
5050
+ await mkdir2(this.questionsDir, { recursive: true });
4801
5051
  const id = this.generateId("q");
4802
5052
  const frontmatter = {
4803
5053
  id,
@@ -4813,8 +5063,8 @@ ${question}
4813
5063
 
4814
5064
  **Context:** ${context}
4815
5065
  `;
4816
- const filePath = path5.join(this.questionsDir, `${id}.md`);
4817
- await writeFile3(filePath, content, "utf-8");
5066
+ const filePath = path4.join(this.questionsDir, `${id}.md`);
5067
+ await writeFile2(filePath, content, "utf-8");
4818
5068
  log.debug(`wrote question ${id} to ${filePath}`);
4819
5069
  this.invalidateQuestionsCache();
4820
5070
  return id;
@@ -4837,8 +5087,8 @@ ${question}
4837
5087
  const questions = [];
4838
5088
  for (const file of files) {
4839
5089
  if (!file.endsWith(".md")) continue;
4840
- const filePath = path5.join(this.questionsDir, file);
4841
- const raw = await readFile3(filePath, "utf-8");
5090
+ const filePath = path4.join(this.questionsDir, file);
5091
+ const raw = await readFile2(filePath, "utf-8");
4842
5092
  const parsed = this.parseQuestionFile(raw, filePath);
4843
5093
  if (parsed) {
4844
5094
  questions.push(parsed);
@@ -4860,7 +5110,7 @@ ${question}
4860
5110
  if (!match) return null;
4861
5111
  const frontmatterStr = match[1];
4862
5112
  const body = match[2].trim();
4863
- const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path5.basename(filePath, ".md");
5113
+ const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path4.basename(filePath, ".md");
4864
5114
  const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
4865
5115
  const priority = parseFloat(
4866
5116
  this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5"
@@ -4881,7 +5131,7 @@ ${question}
4881
5131
  const questions = await this.readQuestions();
4882
5132
  const q = questions.find((q2) => q2.id === id);
4883
5133
  if (!q) return false;
4884
- let raw = await readFile3(q.filePath, "utf-8");
5134
+ let raw = await readFile2(q.filePath, "utf-8");
4885
5135
  raw = raw.replace(/resolved: false/, "resolved: true");
4886
5136
  raw = raw.replace(
4887
5137
  /---\n\n/,
@@ -4890,7 +5140,7 @@ ${question}
4890
5140
 
4891
5141
  `
4892
5142
  );
4893
- await writeFile3(q.filePath, raw, "utf-8");
5143
+ await writeFile2(q.filePath, raw, "utf-8");
4894
5144
  log.debug(`resolved question ${id}`);
4895
5145
  return true;
4896
5146
  }
@@ -4900,14 +5150,14 @@ ${question}
4900
5150
  async readIdentity(workspaceDir, namespace) {
4901
5151
  const identityPath = this.identityFilePath(workspaceDir, namespace);
4902
5152
  try {
4903
- return await readFile3(identityPath, "utf-8");
5153
+ return await readFile2(identityPath, "utf-8");
4904
5154
  } catch {
4905
5155
  return "";
4906
5156
  }
4907
5157
  }
4908
5158
  async writeIdentity(workspaceDir, content, namespace) {
4909
5159
  const identityPath = this.identityFilePath(workspaceDir, namespace);
4910
- await writeFile3(identityPath, content, "utf-8");
5160
+ await writeFile2(identityPath, content, "utf-8");
4911
5161
  log.debug(`wrote consolidated IDENTITY.md (${content.length} chars)`);
4912
5162
  }
4913
5163
  /** Max size for IDENTITY.md before we stop appending reflections (15KB leaves room under 20KB gateway limit) */
@@ -4918,22 +5168,22 @@ ${question}
4918
5168
  const identityPath = this.identityFilePath(workspaceDir, opts?.namespace);
4919
5169
  let existing = "";
4920
5170
  try {
4921
- existing = await readFile3(identityPath, "utf-8");
5171
+ existing = await readFile2(identityPath, "utf-8");
4922
5172
  } catch {
4923
5173
  }
4924
5174
  const hygiene = opts?.hygiene;
4925
- const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path5.basename(identityPath));
5175
+ const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path4.basename(identityPath));
4926
5176
  if (rotateEnabled) {
4927
5177
  const maxBytes = hygiene.rotateMaxBytes;
4928
5178
  if (existing.length > maxBytes) {
4929
- const archiveDir = path5.join(workspaceDir, hygiene.archiveDir);
5179
+ const archiveDir = path4.join(workspaceDir, hygiene.archiveDir);
4930
5180
  const { newContent } = await rotateMarkdownFileToArchive({
4931
5181
  filePath: identityPath,
4932
5182
  archiveDir,
4933
5183
  archivePrefix: "IDENTITY",
4934
5184
  keepTailChars: hygiene.rotateKeepTailChars
4935
5185
  });
4936
- await writeFile3(identityPath, newContent, "utf-8");
5186
+ await writeFile2(identityPath, newContent, "utf-8");
4937
5187
  existing = newContent;
4938
5188
  log.info(
4939
5189
  `rotated IDENTITY.md to archive (size=${existing.length} chars, maxBytes=${maxBytes})`
@@ -4964,24 +5214,24 @@ ${question}
4964
5214
 
4965
5215
  ${reflection}
4966
5216
  `;
4967
- await writeFile3(identityPath, existing + section, "utf-8");
5217
+ await writeFile2(identityPath, existing + section, "utf-8");
4968
5218
  log.debug(`appended reflection to ${identityPath}`);
4969
5219
  }
4970
5220
  async readIdentityReflections() {
4971
5221
  try {
4972
- return await readFile3(this.identityReflectionsPath, "utf-8");
5222
+ return await readFile2(this.identityReflectionsPath, "utf-8");
4973
5223
  } catch {
4974
5224
  return null;
4975
5225
  }
4976
5226
  }
4977
5227
  async writeIdentityReflections(content) {
4978
- await mkdir3(this.identityDir, { recursive: true });
4979
- await writeFile3(this.identityReflectionsPath, content, "utf-8");
5228
+ await mkdir2(this.identityDir, { recursive: true });
5229
+ await writeFile2(this.identityReflectionsPath, content, "utf-8");
4980
5230
  }
4981
5231
  async appendIdentityReflection(reflection) {
4982
5232
  let existing = "";
4983
5233
  try {
4984
- existing = await readFile3(this.identityReflectionsPath, "utf-8");
5234
+ existing = await readFile2(this.identityReflectionsPath, "utf-8");
4985
5235
  } catch {
4986
5236
  }
4987
5237
  if (existing.length > _StorageManager.IDENTITY_MAX_BYTES) {
@@ -5006,8 +5256,8 @@ ${reflection}
5006
5256
 
5007
5257
  ${reflection}
5008
5258
  `;
5009
- await mkdir3(this.identityDir, { recursive: true });
5010
- await writeFile3(this.identityReflectionsPath, `${existing.trimEnd()}${section}`, "utf-8");
5259
+ await mkdir2(this.identityDir, { recursive: true });
5260
+ await writeFile2(this.identityReflectionsPath, `${existing.trimEnd()}${section}`, "utf-8");
5011
5261
  log.debug(`appended namespace-local reflection to ${this.identityReflectionsPath}`);
5012
5262
  }
5013
5263
  // ---------------------------------------------------------------------------
@@ -5018,10 +5268,10 @@ ${reflection}
5018
5268
  * Deduplicates by target+label.
5019
5269
  */
5020
5270
  async addEntityRelationship(name, rel) {
5021
- const filePath = path5.join(this.entitiesDir, `${name}.md`);
5271
+ const filePath = path4.join(this.entitiesDir, `${name}.md`);
5022
5272
  let entity;
5023
5273
  try {
5024
- const content = await readFile3(filePath, "utf-8");
5274
+ const content = await readFile2(filePath, "utf-8");
5025
5275
  entity = parseEntityFile(content, this.entitySchemas);
5026
5276
  } catch {
5027
5277
  log.debug(`addEntityRelationship: entity file ${name}.md not found`);
@@ -5033,7 +5283,7 @@ ${reflection}
5033
5283
  if (exists) return;
5034
5284
  entity.relationships.push(rel);
5035
5285
  entity.updated = (/* @__PURE__ */ new Date()).toISOString();
5036
- await writeFile3(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5286
+ await writeFile2(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5037
5287
  this.invalidateKnowledgeIndexCache();
5038
5288
  }
5039
5289
  /**
@@ -5041,10 +5291,10 @@ ${reflection}
5041
5291
  * Prepends to the beginning, prunes oldest entries beyond maxEntries.
5042
5292
  */
5043
5293
  async addEntityActivity(name, entry, maxEntries) {
5044
- const filePath = path5.join(this.entitiesDir, `${name}.md`);
5294
+ const filePath = path4.join(this.entitiesDir, `${name}.md`);
5045
5295
  let entity;
5046
5296
  try {
5047
- const content = await readFile3(filePath, "utf-8");
5297
+ const content = await readFile2(filePath, "utf-8");
5048
5298
  entity = parseEntityFile(content, this.entitySchemas);
5049
5299
  } catch {
5050
5300
  log.debug(`addEntityActivity: entity file ${name}.md not found`);
@@ -5055,17 +5305,17 @@ ${reflection}
5055
5305
  entity.activity = entity.activity.slice(0, maxEntries);
5056
5306
  }
5057
5307
  entity.updated = (/* @__PURE__ */ new Date()).toISOString();
5058
- await writeFile3(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5308
+ await writeFile2(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5059
5309
  this.invalidateKnowledgeIndexCache();
5060
5310
  }
5061
5311
  /**
5062
5312
  * Add an alias to an entity file. Deduplicates.
5063
5313
  */
5064
5314
  async addEntityAlias(name, alias) {
5065
- const filePath = path5.join(this.entitiesDir, `${name}.md`);
5315
+ const filePath = path4.join(this.entitiesDir, `${name}.md`);
5066
5316
  let entity;
5067
5317
  try {
5068
- const content = await readFile3(filePath, "utf-8");
5318
+ const content = await readFile2(filePath, "utf-8");
5069
5319
  entity = parseEntityFile(content, this.entitySchemas);
5070
5320
  } catch {
5071
5321
  log.debug(`addEntityAlias: entity file ${name}.md not found`);
@@ -5074,17 +5324,17 @@ ${reflection}
5074
5324
  if (entity.aliases.includes(alias)) return;
5075
5325
  entity.aliases.push(alias);
5076
5326
  entity.updated = (/* @__PURE__ */ new Date()).toISOString();
5077
- await writeFile3(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5327
+ await writeFile2(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5078
5328
  this.invalidateKnowledgeIndexCache();
5079
5329
  }
5080
5330
  /**
5081
5331
  * Set or rewrite the synthesis layer of an entity file.
5082
5332
  */
5083
5333
  async updateEntitySynthesis(name, synthesis, options = {}) {
5084
- const filePath = path5.join(this.entitiesDir, `${name}.md`);
5334
+ const filePath = path4.join(this.entitiesDir, `${name}.md`);
5085
5335
  let entity;
5086
5336
  try {
5087
- const content = await readFile3(filePath, "utf-8");
5337
+ const content = await readFile2(filePath, "utf-8");
5088
5338
  entity = parseEntityFile(content, this.entitySchemas);
5089
5339
  } catch {
5090
5340
  log.debug(`updateEntitySynthesis: entity file ${name}.md not found`);
@@ -5103,7 +5353,7 @@ ${reflection}
5103
5353
  entity.synthesisStructuredFactDigest = synthesisStructuredFactDigest;
5104
5354
  entity.synthesisVersion = Math.max(0, entity.synthesisVersion ?? 0) + (options.incrementVersion === false ? 0 : 1);
5105
5355
  entity.updated = entityUpdatedAt;
5106
- await writeFile3(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5356
+ await writeFile2(filePath, serializeEntityFile(entity, this.entitySchemas), "utf-8");
5107
5357
  await this.removeEntitySynthesisQueueEntries([
5108
5358
  .../* @__PURE__ */ new Set([name, normalizeEntityName(entity.name, entity.type)])
5109
5359
  ]);
@@ -5117,8 +5367,8 @@ ${reflection}
5117
5367
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
5118
5368
  let synthesisTimelineCount;
5119
5369
  try {
5120
- const filePath = path5.join(this.entitiesDir, `${name}.md`);
5121
- const content = await readFile3(filePath, "utf-8");
5370
+ const filePath = path4.join(this.entitiesDir, `${name}.md`);
5371
+ const content = await readFile2(filePath, "utf-8");
5122
5372
  synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
5123
5373
  } catch {
5124
5374
  synthesisTimelineCount = void 0;
@@ -5131,7 +5381,7 @@ ${reflection}
5131
5381
  }
5132
5382
  async readEntitySynthesisQueue() {
5133
5383
  try {
5134
- const raw = await readFile3(this.entitySynthesisQueuePath, "utf-8");
5384
+ const raw = await readFile2(this.entitySynthesisQueuePath, "utf-8");
5135
5385
  const parsed = JSON.parse(raw);
5136
5386
  return Array.isArray(parsed.entityNames) ? parsed.entityNames.filter((value) => typeof value === "string") : [];
5137
5387
  } catch {
@@ -5155,8 +5405,8 @@ ${reflection}
5155
5405
  const rightTs = latestEntityTimelineTimestamp(right.entity) ?? "";
5156
5406
  return compareEntityTimestamps(rightTs, leftTs);
5157
5407
  }).map(({ entityName }) => entityName);
5158
- await mkdir3(this.stateDir, { recursive: true });
5159
- await writeFile3(
5408
+ await mkdir2(this.stateDir, { recursive: true });
5409
+ await writeFile2(
5160
5410
  this.entitySynthesisQueuePath,
5161
5411
  JSON.stringify(
5162
5412
  {
@@ -5176,8 +5426,8 @@ ${reflection}
5176
5426
  if (queue.length === 0) return;
5177
5427
  const removals = new Set(entityNames);
5178
5428
  const nextQueue = queue.filter((name) => !removals.has(name));
5179
- await mkdir3(this.stateDir, { recursive: true });
5180
- await writeFile3(
5429
+ await mkdir2(this.stateDir, { recursive: true });
5430
+ await writeFile2(
5181
5431
  this.entitySynthesisQueuePath,
5182
5432
  JSON.stringify(
5183
5433
  {
@@ -5198,7 +5448,7 @@ ${reflection}
5198
5448
  if (!raw) continue;
5199
5449
  const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
5200
5450
  if (raw.trimEnd() === serialized.trimEnd()) continue;
5201
- await writeFile3(path5.join(this.entitiesDir, `${entityName}.md`), serialized, "utf-8");
5451
+ await writeFile2(path4.join(this.entitiesDir, `${entityName}.md`), serialized, "utf-8");
5202
5452
  migrated += 1;
5203
5453
  }
5204
5454
  if (migrated > 0) {
@@ -5232,7 +5482,7 @@ ${reflection}
5232
5482
  const batch = mdFiles.slice(i, i + BATCH_SIZE);
5233
5483
  const results = await Promise.all(
5234
5484
  batch.map(
5235
- (entry) => readFile3(path5.join(this.entitiesDir, entry), "utf-8").catch(() => null)
5485
+ (entry) => readFile2(path4.join(this.entitiesDir, entry), "utf-8").catch(() => null)
5236
5486
  )
5237
5487
  );
5238
5488
  for (const content of results) {
@@ -5372,9 +5622,9 @@ ${rows.join("\n")}
5372
5622
  extraSections: []
5373
5623
  };
5374
5624
  for (const file of files) {
5375
- const filePath = path5.join(this.entitiesDir, file);
5625
+ const filePath = path4.join(this.entitiesDir, file);
5376
5626
  try {
5377
- const content = await readFile3(filePath, "utf-8");
5627
+ const content = await readFile2(filePath, "utf-8");
5378
5628
  const parsed = parseEntityFile(content, this.entitySchemas);
5379
5629
  if (!mergedEntity.type || mergedEntity.type === "other") {
5380
5630
  mergedEntity.type = parsed.type;
@@ -5501,13 +5751,13 @@ ${rows.join("\n")}
5501
5751
  }
5502
5752
  mergedEntity.created = mergedEntity.created || mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
5503
5753
  mergedEntity.updated = mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
5504
- const canonicalPath = path5.join(this.entitiesDir, `${canonical}.md`);
5505
- await writeFile3(canonicalPath, serializeEntityFile(mergedEntity, this.entitySchemas), "utf-8");
5754
+ const canonicalPath = path4.join(this.entitiesDir, `${canonical}.md`);
5755
+ await writeFile2(canonicalPath, serializeEntityFile(mergedEntity, this.entitySchemas), "utf-8");
5506
5756
  for (const file of files) {
5507
- const filePath = path5.join(this.entitiesDir, file);
5757
+ const filePath = path4.join(this.entitiesDir, file);
5508
5758
  if (filePath !== canonicalPath) {
5509
5759
  try {
5510
- await unlink2(filePath);
5760
+ await unlink(filePath);
5511
5761
  merged++;
5512
5762
  log.debug(`merged entity ${file} \u2192 ${canonical}.md`);
5513
5763
  } catch {
@@ -5532,7 +5782,7 @@ ${rows.join("\n")}
5532
5782
  const updatedAt = new Date(m.frontmatter.updated).getTime();
5533
5783
  if (updatedAt < cutoff) {
5534
5784
  try {
5535
- await unlink2(m.path);
5785
+ await unlink(m.path);
5536
5786
  deleted.push(m);
5537
5787
  log.debug(`cleaned expired commitment ${m.frontmatter.id}`);
5538
5788
  } catch {
@@ -5569,7 +5819,7 @@ ${rows.join("\n")}
5569
5819
  ${memory.content}
5570
5820
  `;
5571
5821
  try {
5572
- await writeFile3(memory.path, fileContent, "utf-8");
5822
+ await writeFile2(memory.path, fileContent, "utf-8");
5573
5823
  updated++;
5574
5824
  } catch (err) {
5575
5825
  log.debug(`failed to update access tracking for ${entry.memoryId}: ${err}`);
@@ -5602,7 +5852,7 @@ ${memory.content}
5602
5852
  const filePaths = await this.collectActiveMemoryPaths();
5603
5853
  const foundIds = /* @__PURE__ */ new Set();
5604
5854
  for (const filePath of filePaths) {
5605
- const basename = path5.basename(filePath, ".md");
5855
+ const basename = path4.basename(filePath, ".md");
5606
5856
  if (wantedIds.has(basename)) {
5607
5857
  foundIds.add(basename);
5608
5858
  if (foundIds.size === wantedIds.size) break;
@@ -5700,14 +5950,17 @@ ${sanitized.text}
5700
5950
  `;
5701
5951
  let filePath;
5702
5952
  if (category === "correction") {
5703
- filePath = path5.join(this.correctionsDir, `${id}.md`);
5953
+ filePath = path4.join(this.correctionsDir, `${id}.md`);
5704
5954
  } else if (category === "procedure") {
5705
- await mkdir3(path5.join(this.proceduresDir, today), { recursive: true });
5706
- filePath = path5.join(this.proceduresDir, today, `${id}.md`);
5955
+ await mkdir2(path4.join(this.proceduresDir, today), { recursive: true });
5956
+ filePath = path4.join(this.proceduresDir, today, `${id}.md`);
5957
+ } else if (category === "reasoning_trace") {
5958
+ await mkdir2(path4.join(this.reasoningTracesDir, today), { recursive: true });
5959
+ filePath = path4.join(this.reasoningTracesDir, today, `${id}.md`);
5707
5960
  } else {
5708
- filePath = path5.join(this.factsDir, today, `${id}.md`);
5961
+ filePath = path4.join(this.factsDir, today, `${id}.md`);
5709
5962
  }
5710
- await writeFile3(filePath, fileContent, "utf-8");
5963
+ await writeFile2(filePath, fileContent, "utf-8");
5711
5964
  log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
5712
5965
  return id;
5713
5966
  }
@@ -5743,7 +5996,7 @@ ${sanitized.text}
5743
5996
  ${oldMemory.content}
5744
5997
  `;
5745
5998
  try {
5746
- await writeFile3(oldMemory.path, fileContent, "utf-8");
5999
+ await writeFile2(oldMemory.path, fileContent, "utf-8");
5747
6000
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.supersedeMemory", {
5748
6001
  memoryId: oldMemoryId,
5749
6002
  eventType: "superseded",
@@ -5774,15 +6027,15 @@ Reason: ${reason}`, {
5774
6027
  // Memory Summarization (Phase 4A)
5775
6028
  // ---------------------------------------------------------------------------
5776
6029
  get summariesDir() {
5777
- return path5.join(this.baseDir, "summaries");
6030
+ return path4.join(this.baseDir, "summaries");
5778
6031
  }
5779
6032
  /**
5780
6033
  * Write a memory summary.
5781
6034
  */
5782
6035
  async writeSummary(summary) {
5783
- await mkdir3(this.summariesDir, { recursive: true });
5784
- const filePath = path5.join(this.summariesDir, `${summary.id}.json`);
5785
- await writeFile3(filePath, JSON.stringify(summary, null, 2), "utf-8");
6036
+ await mkdir2(this.summariesDir, { recursive: true });
6037
+ const filePath = path4.join(this.summariesDir, `${summary.id}.json`);
6038
+ await writeFile2(filePath, JSON.stringify(summary, null, 2), "utf-8");
5786
6039
  log.debug(`wrote summary ${summary.id}`);
5787
6040
  }
5788
6041
  /**
@@ -5794,8 +6047,8 @@ Reason: ${reason}`, {
5794
6047
  const summaries = [];
5795
6048
  for (const file of files) {
5796
6049
  if (!file.endsWith(".json")) continue;
5797
- const filePath = path5.join(this.summariesDir, file);
5798
- const raw = await readFile3(filePath, "utf-8");
6050
+ const filePath = path4.join(this.summariesDir, file);
6051
+ const raw = await readFile2(filePath, "utf-8");
5799
6052
  summaries.push(JSON.parse(raw));
5800
6053
  }
5801
6054
  return summaries;
@@ -5825,7 +6078,7 @@ Reason: ${reason}`, {
5825
6078
  ${memory.content}
5826
6079
  `;
5827
6080
  try {
5828
- await writeFile3(memory.path, fileContent, "utf-8");
6081
+ await writeFile2(memory.path, fileContent, "utf-8");
5829
6082
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.archiveMemories", {
5830
6083
  memoryId: id,
5831
6084
  eventType: "archived",
@@ -5853,18 +6106,18 @@ ${memory.content}
5853
6106
  * Save topic scores to meta.json.
5854
6107
  */
5855
6108
  async saveTopics(topics) {
5856
- const metaPath = path5.join(this.stateDir, "topics.json");
5857
- await mkdir3(this.stateDir, { recursive: true });
5858
- await writeFile3(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
6109
+ const metaPath = path4.join(this.stateDir, "topics.json");
6110
+ await mkdir2(this.stateDir, { recursive: true });
6111
+ await writeFile2(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
5859
6112
  log.debug(`saved ${topics.length} topic scores`);
5860
6113
  }
5861
6114
  /**
5862
6115
  * Load topic scores from meta.json.
5863
6116
  */
5864
6117
  async loadTopics() {
5865
- const metaPath = path5.join(this.stateDir, "topics.json");
6118
+ const metaPath = path4.join(this.stateDir, "topics.json");
5866
6119
  try {
5867
- const raw = await readFile3(metaPath, "utf-8");
6120
+ const raw = await readFile2(metaPath, "utf-8");
5868
6121
  return JSON.parse(raw);
5869
6122
  } catch {
5870
6123
  return { topics: [], updatedAt: null };
@@ -5953,6 +6206,7 @@ export {
5953
6206
  setCachedQmdSearch,
5954
6207
  lintWorkspaceFiles,
5955
6208
  rotateMarkdownFileToArchive,
6209
+ isConsolidationOperator,
5956
6210
  confidenceTier,
5957
6211
  openBetterSqlite3,
5958
6212
  MEMORY_PROJECTION_SCHEMA_VERSION,