From 8c93745f0fc5f2083a0b3a344fb6c3309cc10249 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 25 Apr 2026 18:41:01 +0100 Subject: [PATCH] test(memory): speed up host fixture setup --- .../memory-host-sdk/src/host/internal.test.ts | 96 +++++++++---------- .../src/host/session-files.test.ts | 28 +++--- src/memory-host-sdk/host/internal.test.ts | 95 +++++++++--------- .../host/session-files.test.ts | 70 +++++++------- 4 files changed, 145 insertions(+), 144 deletions(-) diff --git a/packages/memory-host-sdk/src/host/internal.test.ts b/packages/memory-host-sdk/src/host/internal.test.ts index e67adf45789..6de9b5ee7df 100644 --- a/packages/memory-host-sdk/src/host/internal.test.ts +++ b/packages/memory-host-sdk/src/host/internal.test.ts @@ -1,4 +1,4 @@ -import fs from "node:fs/promises"; +import fsSync from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -19,21 +19,21 @@ import { let sharedTempRoot = ""; let sharedTempId = 0; -beforeAll(async () => { - sharedTempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "memory-host-sdk-tests-")); +beforeAll(() => { + sharedTempRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "memory-host-sdk-tests-")); }); -afterAll(async () => { +afterAll(() => { if (sharedTempRoot) { - await fs.rm(sharedTempRoot, { recursive: true, force: true }); + fsSync.rmSync(sharedTempRoot, { recursive: true, force: true }); } }); function setupTempDirLifecycle(prefix: string): () => string { let tmpDir = ""; - beforeEach(async () => { + beforeEach(() => { tmpDir = path.join(sharedTempRoot, `${prefix}${sharedTempId++}`); - await fs.mkdir(tmpDir, { recursive: true }); + fsSync.mkdirSync(tmpDir, { recursive: true }); }); return () => tmpDir; } @@ -63,12 +63,12 @@ describe("listMemoryFiles", () => { it("includes files from additional paths (directory)", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "extra-notes"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "note1.md"), "# Note 1"); - await fs.writeFile(path.join(extraDir, "note2.md"), "# Note 2"); - await fs.writeFile(path.join(extraDir, "ignore.txt"), "Not a markdown file"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "note1.md"), "# Note 1"); + fsSync.writeFileSync(path.join(extraDir, "note2.md"), "# Note 2"); + fsSync.writeFileSync(path.join(extraDir, "ignore.txt"), "Not a markdown file"); const files = await listMemoryFiles(tmpDir, [extraDir]); expect(files).toHaveLength(3); @@ -80,9 +80,9 @@ describe("listMemoryFiles", () => { it("includes files from additional paths (single file)", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const singleFile = path.join(tmpDir, "standalone.md"); - await fs.writeFile(singleFile, "# Standalone"); + fsSync.writeFileSync(singleFile, "# Standalone"); const files = await listMemoryFiles(tmpDir, [singleFile]); expect(files).toHaveLength(2); @@ -91,7 +91,7 @@ describe("listMemoryFiles", () => { it("ignores lowercase root memory.md when canonical MEMORY.md is absent", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "memory.md"), "# Legacy memory"); + fsSync.writeFileSync(path.join(tmpDir, "memory.md"), "# Legacy memory"); const files = await listMemoryFiles(tmpDir, [path.join(tmpDir, "memory.md")]); @@ -100,8 +100,8 @@ describe("listMemoryFiles", () => { it("prefers MEMORY.md when both root files exist", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); - await fs.writeFile(path.join(tmpDir, "memory.md"), "# Legacy memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "memory.md"), "# Legacy memory"); const files = await listMemoryFiles(tmpDir, [path.join(tmpDir, "memory.md"), tmpDir]); @@ -110,10 +110,10 @@ describe("listMemoryFiles", () => { it("skips root-memory repair backups from extra workspace paths", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const repairDir = path.join(tmpDir, ".openclaw-repair", "root-memory", "2026-04-23"); - await fs.mkdir(repairDir, { recursive: true }); - await fs.writeFile(path.join(repairDir, "memory.md"), "# Archived legacy memory"); + fsSync.mkdirSync(repairDir, { recursive: true }); + fsSync.writeFileSync(path.join(repairDir, "memory.md"), "# Archived legacy memory"); const files = await listMemoryFiles(tmpDir, [tmpDir]); @@ -123,10 +123,10 @@ describe("listMemoryFiles", () => { it("handles relative paths in additional paths", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "subdir"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "nested.md"), "# Nested"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "nested.md"), "# Nested"); const files = await listMemoryFiles(tmpDir, ["subdir"]); expect(files).toHaveLength(2); @@ -135,7 +135,7 @@ describe("listMemoryFiles", () => { it("ignores non-existent additional paths", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const files = await listMemoryFiles(tmpDir, ["/does/not/exist"]); expect(files).toHaveLength(1); @@ -143,24 +143,24 @@ describe("listMemoryFiles", () => { it("ignores symlinked files and directories", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "extra"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "note.md"), "# Note"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "note.md"), "# Note"); const targetFile = path.join(tmpDir, "target.md"); - await fs.writeFile(targetFile, "# Target"); + fsSync.writeFileSync(targetFile, "# Target"); const linkFile = path.join(extraDir, "linked.md"); const targetDir = path.join(tmpDir, "target-dir"); - await fs.mkdir(targetDir, { recursive: true }); - await fs.writeFile(path.join(targetDir, "nested.md"), "# Nested"); + fsSync.mkdirSync(targetDir, { recursive: true }); + fsSync.writeFileSync(path.join(targetDir, "nested.md"), "# Nested"); const linkDir = path.join(tmpDir, "linked-dir"); let symlinksOk = true; try { - await fs.symlink(targetFile, linkFile, "file"); - await fs.symlink(targetDir, linkDir, "dir"); + fsSync.symlinkSync(targetFile, linkFile, "file"); + fsSync.symlinkSync(targetDir, linkDir, "dir"); } catch (err) { const code = (err as NodeJS.ErrnoException).code; if (code === "EPERM" || code === "EACCES") { @@ -180,7 +180,7 @@ describe("listMemoryFiles", () => { it("dedupes overlapping extra paths that resolve to the same file", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const files = await listMemoryFiles(tmpDir, [tmpDir, ".", path.join(tmpDir, "MEMORY.md")]); const memoryMatches = files.filter((file) => file.endsWith("MEMORY.md")); expect(memoryMatches).toHaveLength(1); @@ -189,10 +189,10 @@ describe("listMemoryFiles", () => { it("includes image and audio files from extra paths when multimodal is enabled", async () => { const tmpDir = getTmpDir(); const extraDir = path.join(tmpDir, "media"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "diagram.png"), Buffer.from("png")); - await fs.writeFile(path.join(extraDir, "note.wav"), Buffer.from("wav")); - await fs.writeFile(path.join(extraDir, "ignore.bin"), Buffer.from("bin")); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "diagram.png"), Buffer.from("png")); + fsSync.writeFileSync(path.join(extraDir, "note.wav"), Buffer.from("wav")); + fsSync.writeFileSync(path.join(extraDir, "ignore.bin"), Buffer.from("bin")); const files = await listMemoryFiles(tmpDir, [extraDir], multimodal); expect(files.some((file) => file.endsWith("diagram.png"))).toBe(true); @@ -218,8 +218,8 @@ describe("buildFileEntry", () => { it("returns null when the file disappears before reading", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "ghost.md"); - await fs.writeFile(target, "ghost", "utf-8"); - await fs.rm(target); + fsSync.writeFileSync(target, "ghost", "utf-8"); + fsSync.rmSync(target); const entry = await buildFileEntry(target, tmpDir); expect(entry).toBeNull(); }); @@ -227,7 +227,7 @@ describe("buildFileEntry", () => { it("returns metadata when the file exists", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "note.md"); - await fs.writeFile(target, "hello", "utf-8"); + fsSync.writeFileSync(target, "hello", "utf-8"); const entry = await buildFileEntry(target, tmpDir); expect(entry).not.toBeNull(); expect(entry?.path).toBe("note.md"); @@ -237,7 +237,7 @@ describe("buildFileEntry", () => { it("returns multimodal metadata for eligible image files", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "diagram.png"); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); @@ -253,7 +253,7 @@ describe("buildFileEntry", () => { it("builds a multimodal chunk lazily for indexing", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "diagram.png"); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); const built = await buildMultimodalChunkForIndexing(entry!); @@ -269,24 +269,24 @@ describe("buildFileEntry", () => { for (const testCase of [ { name: "grows", - mutate: async (target: string, entrySize: number) => { - await fs.writeFile(target, Buffer.alloc(entrySize + 32, 1)); + mutate: (target: string, entrySize: number) => { + fsSync.writeFileSync(target, Buffer.alloc(entrySize + 32, 1)); }, }, { name: "bytes change", - mutate: async (target: string) => { - await fs.writeFile(target, Buffer.from("gif")); + mutate: (target: string) => { + fsSync.writeFileSync(target, Buffer.from("gif")); }, }, ] as const) { const tmpDir = getTmpDir(); const target = path.join(tmpDir, `${testCase.name}.png`); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); expect(entry, testCase.name).not.toBeNull(); - await testCase.mutate(target, entry!.size); + testCase.mutate(target, entry!.size); await expect(buildMultimodalChunkForIndexing(entry!), testCase.name).resolves.toBeNull(); } diff --git a/packages/memory-host-sdk/src/host/session-files.test.ts b/packages/memory-host-sdk/src/host/session-files.test.ts index 447ed2db407..0d85589263b 100644 --- a/packages/memory-host-sdk/src/host/session-files.test.ts +++ b/packages/memory-host-sdk/src/host/session-files.test.ts @@ -1,4 +1,4 @@ -import fs from "node:fs/promises"; +import fsSync from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -9,17 +9,17 @@ let tmpDir: string; let originalStateDir: string | undefined; let fixtureId = 0; -beforeAll(async () => { - fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "session-entry-test-")); +beforeAll(() => { + fixtureRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "session-entry-test-")); }); -afterAll(async () => { - await fs.rm(fixtureRoot, { recursive: true, force: true }); +afterAll(() => { + fsSync.rmSync(fixtureRoot, { recursive: true, force: true }); }); -beforeEach(async () => { +beforeEach(() => { tmpDir = path.join(fixtureRoot, `case-${fixtureId++}`); - await fs.mkdir(tmpDir, { recursive: true }); + fsSync.mkdirSync(tmpDir, { recursive: true }); originalStateDir = process.env.OPENCLAW_STATE_DIR; process.env.OPENCLAW_STATE_DIR = tmpDir; }); @@ -35,7 +35,7 @@ afterEach(() => { describe("listSessionFilesForAgent", () => { it("includes reset and deleted transcripts in session file listing", async () => { const sessionsDir = path.join(tmpDir, "agents", "main", "sessions"); - await fs.mkdir(path.join(sessionsDir, "archive"), { recursive: true }); + fsSync.mkdirSync(path.join(sessionsDir, "archive"), { recursive: true }); const included = [ "active.jsonl", @@ -45,9 +45,9 @@ describe("listSessionFilesForAgent", () => { const excluded = ["active.jsonl.bak.2026-02-16T22-28-33.000Z", "sessions.json", "notes.md"]; for (const fileName of [...included, ...excluded]) { - await fs.writeFile(path.join(sessionsDir, fileName), ""); + fsSync.writeFileSync(path.join(sessionsDir, fileName), ""); } - await fs.writeFile( + fsSync.writeFileSync( path.join(sessionsDir, "archive", "nested.jsonl.deleted.2026-02-16T22-29-33.000Z"), "", ); @@ -81,7 +81,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "message", message: { role: "user", content: "Tell me a joke" } }), ]; const filePath = path.join(tmpDir, "session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -107,7 +107,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "session-meta", agentId: "test" }), ]; const filePath = path.join(tmpDir, "empty-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -124,7 +124,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "message", message: { role: "assistant", content: "Second" } }), ]; const filePath = path.join(tmpDir, "gaps.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -154,7 +154,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "enveloped-session-array.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); diff --git a/src/memory-host-sdk/host/internal.test.ts b/src/memory-host-sdk/host/internal.test.ts index 603cc87f67e..ffbe04db7d3 100644 --- a/src/memory-host-sdk/host/internal.test.ts +++ b/src/memory-host-sdk/host/internal.test.ts @@ -1,3 +1,4 @@ +import fsSync from "node:fs"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; @@ -19,21 +20,21 @@ import { let sharedTempRoot = ""; let sharedTempId = 0; -beforeAll(async () => { - sharedTempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "memory-host-sdk-tests-")); +beforeAll(() => { + sharedTempRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "memory-host-sdk-tests-")); }); -afterAll(async () => { +afterAll(() => { if (sharedTempRoot) { - await fs.rm(sharedTempRoot, { recursive: true, force: true }); + fsSync.rmSync(sharedTempRoot, { recursive: true, force: true }); } }); function setupTempDirLifecycle(prefix: string): () => string { let tmpDir = ""; - beforeEach(async () => { + beforeEach(() => { tmpDir = path.join(sharedTempRoot, `${prefix}${sharedTempId++}`); - await fs.mkdir(tmpDir, { recursive: true }); + fsSync.mkdirSync(tmpDir, { recursive: true }); }); return () => tmpDir; } @@ -63,12 +64,12 @@ describe("listMemoryFiles", () => { it("includes files from additional paths (directory)", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "extra-notes"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "note1.md"), "# Note 1"); - await fs.writeFile(path.join(extraDir, "note2.md"), "# Note 2"); - await fs.writeFile(path.join(extraDir, "ignore.txt"), "Not a markdown file"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "note1.md"), "# Note 1"); + fsSync.writeFileSync(path.join(extraDir, "note2.md"), "# Note 2"); + fsSync.writeFileSync(path.join(extraDir, "ignore.txt"), "Not a markdown file"); const files = await listMemoryFiles(tmpDir, [extraDir]); expect(files).toHaveLength(3); @@ -80,9 +81,9 @@ describe("listMemoryFiles", () => { it("includes files from additional paths (single file)", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const singleFile = path.join(tmpDir, "standalone.md"); - await fs.writeFile(singleFile, "# Standalone"); + fsSync.writeFileSync(singleFile, "# Standalone"); const files = await listMemoryFiles(tmpDir, [singleFile]); expect(files).toHaveLength(2); @@ -91,7 +92,7 @@ describe("listMemoryFiles", () => { it("ignores lowercase root memory.md when canonical MEMORY.md is absent", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "memory.md"), "# Legacy memory"); + fsSync.writeFileSync(path.join(tmpDir, "memory.md"), "# Legacy memory"); const files = await listMemoryFiles(tmpDir, [path.join(tmpDir, "memory.md")]); @@ -164,10 +165,10 @@ describe("listMemoryFiles", () => { }, ] as const) { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const repairDir = path.join(tmpDir, ".openclaw-repair", "root-memory", "2026-04-23"); - await fs.mkdir(repairDir, { recursive: true }); - await fs.writeFile(path.join(repairDir, "memory.md"), "# Archived legacy memory"); + fsSync.mkdirSync(repairDir, { recursive: true }); + fsSync.writeFileSync(path.join(repairDir, "memory.md"), "# Archived legacy memory"); const files = await listMemoryFiles(tmpDir, testCase.extraPaths(tmpDir)); @@ -178,10 +179,10 @@ describe("listMemoryFiles", () => { it("handles relative paths in additional paths", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "subdir"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "nested.md"), "# Nested"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "nested.md"), "# Nested"); const files = await listMemoryFiles(tmpDir, ["subdir"]); expect(files).toHaveLength(2); @@ -190,7 +191,7 @@ describe("listMemoryFiles", () => { it("ignores non-existent additional paths", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const files = await listMemoryFiles(tmpDir, ["/does/not/exist"]); expect(files).toHaveLength(1); @@ -198,24 +199,24 @@ describe("listMemoryFiles", () => { it("ignores symlinked files and directories", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const extraDir = path.join(tmpDir, "extra"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "note.md"), "# Note"); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "note.md"), "# Note"); const targetFile = path.join(tmpDir, "target.md"); - await fs.writeFile(targetFile, "# Target"); + fsSync.writeFileSync(targetFile, "# Target"); const linkFile = path.join(extraDir, "linked.md"); const targetDir = path.join(tmpDir, "target-dir"); - await fs.mkdir(targetDir, { recursive: true }); - await fs.writeFile(path.join(targetDir, "nested.md"), "# Nested"); + fsSync.mkdirSync(targetDir, { recursive: true }); + fsSync.writeFileSync(path.join(targetDir, "nested.md"), "# Nested"); const linkDir = path.join(tmpDir, "linked-dir"); let symlinksOk = true; try { - await fs.symlink(targetFile, linkFile, "file"); - await fs.symlink(targetDir, linkDir, "dir"); + fsSync.symlinkSync(targetFile, linkFile, "file"); + fsSync.symlinkSync(targetDir, linkDir, "dir"); } catch (err) { const code = (err as NodeJS.ErrnoException).code; if (code === "EPERM" || code === "EACCES") { @@ -235,7 +236,7 @@ describe("listMemoryFiles", () => { it("dedupes overlapping extra paths that resolve to the same file", async () => { const tmpDir = getTmpDir(); - await fs.writeFile(path.join(tmpDir, "MEMORY.md"), "# Default memory"); + fsSync.writeFileSync(path.join(tmpDir, "MEMORY.md"), "# Default memory"); const files = await listMemoryFiles(tmpDir, [tmpDir, ".", path.join(tmpDir, "MEMORY.md")]); const memoryMatches = files.filter((file) => file.endsWith("MEMORY.md")); expect(memoryMatches).toHaveLength(1); @@ -244,10 +245,10 @@ describe("listMemoryFiles", () => { it("includes image and audio files from extra paths when multimodal is enabled", async () => { const tmpDir = getTmpDir(); const extraDir = path.join(tmpDir, "media"); - await fs.mkdir(extraDir, { recursive: true }); - await fs.writeFile(path.join(extraDir, "diagram.png"), Buffer.from("png")); - await fs.writeFile(path.join(extraDir, "note.wav"), Buffer.from("wav")); - await fs.writeFile(path.join(extraDir, "ignore.bin"), Buffer.from("bin")); + fsSync.mkdirSync(extraDir, { recursive: true }); + fsSync.writeFileSync(path.join(extraDir, "diagram.png"), Buffer.from("png")); + fsSync.writeFileSync(path.join(extraDir, "note.wav"), Buffer.from("wav")); + fsSync.writeFileSync(path.join(extraDir, "ignore.bin"), Buffer.from("bin")); const files = await listMemoryFiles(tmpDir, [extraDir], multimodal); expect(files.some((file) => file.endsWith("diagram.png"))).toBe(true); @@ -273,8 +274,8 @@ describe("buildFileEntry", () => { it("returns null when the file disappears before reading", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "ghost.md"); - await fs.writeFile(target, "ghost", "utf-8"); - await fs.rm(target); + fsSync.writeFileSync(target, "ghost", "utf-8"); + fsSync.rmSync(target); const entry = await buildFileEntry(target, tmpDir); expect(entry).toBeNull(); }); @@ -282,7 +283,7 @@ describe("buildFileEntry", () => { it("returns metadata when the file exists", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "note.md"); - await fs.writeFile(target, "hello", "utf-8"); + fsSync.writeFileSync(target, "hello", "utf-8"); const entry = await buildFileEntry(target, tmpDir); expect(entry).not.toBeNull(); expect(entry?.path).toBe("note.md"); @@ -292,7 +293,7 @@ describe("buildFileEntry", () => { it("returns multimodal metadata for eligible image files", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "diagram.png"); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); @@ -308,7 +309,7 @@ describe("buildFileEntry", () => { it("builds a multimodal chunk lazily for indexing", async () => { const tmpDir = getTmpDir(); const target = path.join(tmpDir, "diagram.png"); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); const built = await buildMultimodalChunkForIndexing(entry!); @@ -324,30 +325,30 @@ describe("buildFileEntry", () => { for (const testCase of [ { name: "grows", - mutate: async (target: string, entrySize: number) => { - await fs.writeFile(target, Buffer.alloc(entrySize + 32, 1)); + mutate: (target: string, entrySize: number) => { + fsSync.writeFileSync(target, Buffer.alloc(entrySize + 32, 1)); }, }, { name: "bytes change", - mutate: async (target: string) => { - await fs.writeFile(target, Buffer.from("gif")); + mutate: (target: string) => { + fsSync.writeFileSync(target, Buffer.from("gif")); }, }, { name: "disappears", - mutate: async (target: string) => { - await fs.rm(target); + mutate: (target: string) => { + fsSync.rmSync(target); }, }, ] as const) { const tmpDir = getTmpDir(); const target = path.join(tmpDir, `${testCase.name}.png`); - await fs.writeFile(target, Buffer.from("png")); + fsSync.writeFileSync(target, Buffer.from("png")); const entry = await buildFileEntry(target, tmpDir, multimodal); expect(entry, testCase.name).not.toBeNull(); - await testCase.mutate(target, entry!.size); + testCase.mutate(target, entry!.size); await expect(buildMultimodalChunkForIndexing(entry!), testCase.name).resolves.toBeNull(); } diff --git a/src/memory-host-sdk/host/session-files.test.ts b/src/memory-host-sdk/host/session-files.test.ts index 2273f643f86..735ec02ef53 100644 --- a/src/memory-host-sdk/host/session-files.test.ts +++ b/src/memory-host-sdk/host/session-files.test.ts @@ -1,4 +1,4 @@ -import fs from "node:fs/promises"; +import fsSync from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -9,17 +9,17 @@ let tmpDir: string; let originalStateDir: string | undefined; let fixtureId = 0; -beforeAll(async () => { - fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "session-entry-test-")); +beforeAll(() => { + fixtureRoot = fsSync.mkdtempSync(path.join(os.tmpdir(), "session-entry-test-")); }); -afterAll(async () => { - await fs.rm(fixtureRoot, { recursive: true, force: true }); +afterAll(() => { + fsSync.rmSync(fixtureRoot, { recursive: true, force: true }); }); -beforeEach(async () => { +beforeEach(() => { tmpDir = path.join(fixtureRoot, `case-${fixtureId++}`); - await fs.mkdir(tmpDir, { recursive: true }); + fsSync.mkdirSync(tmpDir, { recursive: true }); originalStateDir = process.env.OPENCLAW_STATE_DIR; process.env.OPENCLAW_STATE_DIR = tmpDir; }); @@ -47,16 +47,16 @@ function expectNoUnpairedSurrogates(value: string): void { } } -async function writeSessionJsonl(fileName: string, records: readonly unknown[]): Promise { +function writeSessionJsonl(fileName: string, records: readonly unknown[]): string { const filePath = path.join(tmpDir, fileName); - await fs.writeFile(filePath, records.map((record) => JSON.stringify(record)).join("\n")); + fsSync.writeFileSync(filePath, records.map((record) => JSON.stringify(record)).join("\n")); return filePath; } describe("listSessionFilesForAgent", () => { it("includes reset and deleted transcripts in session file listing", async () => { const sessionsDir = path.join(tmpDir, "agents", "main", "sessions"); - await fs.mkdir(path.join(sessionsDir, "archive"), { recursive: true }); + fsSync.mkdirSync(path.join(sessionsDir, "archive"), { recursive: true }); const included = [ "active.jsonl", @@ -66,9 +66,9 @@ describe("listSessionFilesForAgent", () => { const excluded = ["active.jsonl.bak.2026-02-16T22-28-33.000Z", "sessions.json", "notes.md"]; for (const fileName of [...included, ...excluded]) { - await fs.writeFile(path.join(sessionsDir, fileName), ""); + fsSync.writeFileSync(path.join(sessionsDir, fileName), ""); } - await fs.writeFile( + fsSync.writeFileSync( path.join(sessionsDir, "archive", "nested.jsonl.deleted.2026-02-16T22-29-33.000Z"), "", ); @@ -102,7 +102,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "message", message: { role: "user", content: "Tell me a joke" } }), ]; const filePath = path.join(tmpDir, "session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -129,7 +129,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "session-meta", agentId: "test" }), ]; const filePath = path.join(tmpDir, "empty-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -147,7 +147,7 @@ describe("buildSessionEntry", () => { JSON.stringify({ type: "message", message: { role: "assistant", content: "Second" } }), ]; const filePath = path.join(tmpDir, "gaps.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -172,7 +172,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "timestamps.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -213,7 +213,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "enveloped-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -251,7 +251,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "enveloped-session-array.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -269,7 +269,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "wrapped-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -291,7 +291,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "hard-wrapped-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -315,7 +315,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "surrogate-safe-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -342,7 +342,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "assistant-sentinel.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); expect(entry).not.toBeNull(); @@ -365,7 +365,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "dreaming-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); @@ -375,9 +375,9 @@ describe("buildSessionEntry", () => { it("flags cron run transcripts from the sibling session store and skips their content", async () => { const sessionsDir = path.join(tmpDir, "agents", "main", "sessions"); - await fs.mkdir(sessionsDir, { recursive: true }); + fsSync.mkdirSync(sessionsDir, { recursive: true }); const filePath = path.join(sessionsDir, "cron-run-session.jsonl"); - await fs.writeFile( + fsSync.writeFileSync( filePath, [ JSON.stringify({ @@ -396,7 +396,7 @@ describe("buildSessionEntry", () => { }), ].join("\n"), ); - await fs.writeFile( + fsSync.writeFileSync( path.join(sessionsDir, "sessions.json"), JSON.stringify({ "agent:main:cron:job-1:run:run-1": { @@ -418,9 +418,9 @@ describe("buildSessionEntry", () => { it("flags dreaming narrative transcripts from the sibling session store before bootstrap lands", async () => { const sessionsDir = path.join(tmpDir, "agents", "main", "sessions"); - await fs.mkdir(sessionsDir, { recursive: true }); + fsSync.mkdirSync(sessionsDir, { recursive: true }); const filePath = path.join(sessionsDir, "dreaming-session.jsonl"); - await fs.writeFile( + fsSync.writeFileSync( filePath, [ JSON.stringify({ @@ -440,7 +440,7 @@ describe("buildSessionEntry", () => { }), ].join("\n"), ); - await fs.writeFile( + fsSync.writeFileSync( path.join(sessionsDir, "sessions.json"), JSON.stringify({ "agent:main:dreaming-narrative-light-1775894400455": { @@ -476,7 +476,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "dreaming-prompt-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); @@ -594,7 +594,7 @@ describe("buildSessionEntry", () => { ] as const; for (const testCase of cases) { - const filePath = await writeSessionJsonl(testCase.fileName, testCase.records); + const filePath = writeSessionJsonl(testCase.fileName, testCase.records); const entry = await buildSessionEntry(filePath); expect(entry, testCase.name).not.toBeNull(); @@ -624,7 +624,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "spoof-attempt-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath); @@ -641,8 +641,8 @@ describe("buildSessionEntry", () => { type: "message", message: { role: "user", content: "This should never reach the dreaming corpus." }, }); - await fs.writeFile(deletedPath, content); - await fs.writeFile(checkpointPath, content); + fsSync.writeFileSync(deletedPath, content); + fsSync.writeFileSync(checkpointPath, content); const deletedEntry = await buildSessionEntry(deletedPath); const checkpointEntry = await buildSessionEntry(checkpointPath); @@ -670,7 +670,7 @@ describe("buildSessionEntry", () => { }), ]; const filePath = path.join(tmpDir, "substring-marker-session.jsonl"); - await fs.writeFile(filePath, jsonlLines.join("\n")); + fsSync.writeFileSync(filePath, jsonlLines.join("\n")); const entry = await buildSessionEntry(filePath);