Merge 2f9bcb6a71 into da71eaebd2
This commit is contained in:
commit
e5019dc02c
@ -1,8 +1,16 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
DEFAULT_AGENTS_FILENAME,
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_MEMORY_ALT_FILENAME,
|
||||
DEFAULT_MEMORY_DIR,
|
||||
DEFAULT_MEMORY_FILENAME,
|
||||
DEFAULT_SOUL_FILENAME,
|
||||
DEFAULT_USER_FILENAME,
|
||||
ensureAgentWorkspace,
|
||||
loadWorkspaceBootstrapFiles,
|
||||
} from "./workspace.js";
|
||||
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
|
||||
@ -47,3 +55,62 @@ describe("loadWorkspaceBootstrapFiles", () => {
|
||||
expect(memoryEntries).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureAgentWorkspace", () => {
|
||||
it("creates memory directory with symlinks to identity files", async () => {
|
||||
const tempDir = await makeTempWorkspace("moltbot-workspace-");
|
||||
|
||||
const result = await ensureAgentWorkspace({
|
||||
dir: tempDir,
|
||||
ensureBootstrapFiles: true,
|
||||
});
|
||||
|
||||
// Check memory directory was created
|
||||
expect(result.memoryDir).toBe(path.join(tempDir, DEFAULT_MEMORY_DIR));
|
||||
const memoryDirStat = await fs.stat(result.memoryDir!);
|
||||
expect(memoryDirStat.isDirectory()).toBe(true);
|
||||
|
||||
// Check symlinks exist in memory directory
|
||||
const memoryFiles = await fs.readdir(result.memoryDir!);
|
||||
expect(memoryFiles).toContain(DEFAULT_SOUL_FILENAME);
|
||||
expect(memoryFiles).toContain(DEFAULT_USER_FILENAME);
|
||||
expect(memoryFiles).toContain(DEFAULT_AGENTS_FILENAME);
|
||||
expect(memoryFiles).toContain(DEFAULT_IDENTITY_FILENAME);
|
||||
|
||||
// Check symlinks point to correct files
|
||||
const soulLink = await fs.readlink(path.join(result.memoryDir!, DEFAULT_SOUL_FILENAME));
|
||||
expect(soulLink).toBe(`../${DEFAULT_SOUL_FILENAME}`);
|
||||
});
|
||||
|
||||
it("does not create memory directory when ensureBootstrapFiles is false", async () => {
|
||||
const tempDir = await makeTempWorkspace("moltbot-workspace-");
|
||||
|
||||
const result = await ensureAgentWorkspace({
|
||||
dir: tempDir,
|
||||
ensureBootstrapFiles: false,
|
||||
});
|
||||
|
||||
expect(result.memoryDir).toBeUndefined();
|
||||
const memoryDirPath = path.join(tempDir, DEFAULT_MEMORY_DIR);
|
||||
await expect(fs.access(memoryDirPath)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("does not overwrite existing files in memory directory", async () => {
|
||||
const tempDir = await makeTempWorkspace("moltbot-workspace-");
|
||||
const memoryDir = path.join(tempDir, DEFAULT_MEMORY_DIR);
|
||||
await fs.mkdir(memoryDir, { recursive: true });
|
||||
|
||||
// Create an existing file in memory directory
|
||||
const existingContent = "existing content";
|
||||
await fs.writeFile(path.join(memoryDir, DEFAULT_SOUL_FILENAME), existingContent);
|
||||
|
||||
await ensureAgentWorkspace({
|
||||
dir: tempDir,
|
||||
ensureBootstrapFiles: true,
|
||||
});
|
||||
|
||||
// Check existing file was not overwritten
|
||||
const content = await fs.readFile(path.join(memoryDir, DEFAULT_SOUL_FILENAME), "utf-8");
|
||||
expect(content).toBe(existingContent);
|
||||
});
|
||||
});
|
||||
|
||||
@ -28,6 +28,7 @@ export const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
||||
export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
||||
export const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
||||
export const DEFAULT_MEMORY_ALT_FILENAME = "memory.md";
|
||||
export const DEFAULT_MEMORY_DIR = "memory";
|
||||
|
||||
const TEMPLATE_DIR = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
@ -120,6 +121,7 @@ export async function ensureAgentWorkspace(params?: {
|
||||
ensureBootstrapFiles?: boolean;
|
||||
}): Promise<{
|
||||
dir: string;
|
||||
memoryDir?: string;
|
||||
agentsPath?: string;
|
||||
soulPath?: string;
|
||||
toolsPath?: string;
|
||||
@ -174,10 +176,39 @@ export async function ensureAgentWorkspace(params?: {
|
||||
if (isBrandNewWorkspace) {
|
||||
await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
|
||||
}
|
||||
|
||||
// Ensure memory/ directory exists and symlink identity files for memory search indexing
|
||||
const memoryDir = path.join(dir, DEFAULT_MEMORY_DIR);
|
||||
await fs.mkdir(memoryDir, { recursive: true });
|
||||
|
||||
// Symlink identity files into memory/ so they are indexed by memory search
|
||||
const identityFilesToSymlink = [
|
||||
{ source: soulPath, target: path.join(memoryDir, DEFAULT_SOUL_FILENAME) },
|
||||
{ source: userPath, target: path.join(memoryDir, DEFAULT_USER_FILENAME) },
|
||||
{ source: agentsPath, target: path.join(memoryDir, DEFAULT_AGENTS_FILENAME) },
|
||||
{ source: identityPath, target: path.join(memoryDir, DEFAULT_IDENTITY_FILENAME) },
|
||||
];
|
||||
|
||||
for (const { source, target } of identityFilesToSymlink) {
|
||||
try {
|
||||
await fs.access(target);
|
||||
// Target already exists, skip
|
||||
} catch {
|
||||
// Target doesn't exist, create symlink
|
||||
try {
|
||||
const relativePath = path.relative(memoryDir, source);
|
||||
await fs.symlink(relativePath, target);
|
||||
} catch {
|
||||
// Symlink creation failed (e.g., on Windows without privileges), skip silently
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ensureGitRepo(dir, isBrandNewWorkspace);
|
||||
|
||||
return {
|
||||
dir,
|
||||
memoryDir,
|
||||
agentsPath,
|
||||
soulPath,
|
||||
toolsPath,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user