feat(FN-1692): merge fusion/fn-1692
This commit is contained in:
@@ -7,6 +7,7 @@ import { AgentStore } from "../agent-store.js";
|
||||
describe("AgentStore — instructions bundle", () => {
|
||||
let testDir: string;
|
||||
let store: AgentStore;
|
||||
const createdAgentIds: string[] = [];
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = await mkdtemp(join(tmpdir(), "agent-instructions-bundle-test-"));
|
||||
@@ -15,7 +16,23 @@ describe("AgentStore — instructions bundle", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(testDir, { recursive: true, force: true });
|
||||
// Teardown order: entity cleanup first, then filesystem
|
||||
// Delete all created agents explicitly
|
||||
for (const agentId of createdAgentIds) {
|
||||
try {
|
||||
await store.deleteAgent(agentId);
|
||||
} catch {
|
||||
// Ignore cleanup errors for already-removed entities
|
||||
}
|
||||
}
|
||||
createdAgentIds.length = 0;
|
||||
|
||||
// Filesystem cleanup last
|
||||
try {
|
||||
await rm(testDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
it("persists bundleConfig through create + load roundtrip", async () => {
|
||||
@@ -28,6 +45,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
files: ["AGENTS.md", "STYLE.md"],
|
||||
},
|
||||
});
|
||||
createdAgentIds.push(created.id);
|
||||
|
||||
expect(created.bundleConfig).toEqual({
|
||||
mode: "managed",
|
||||
@@ -41,11 +59,13 @@ describe("AgentStore — instructions bundle", () => {
|
||||
|
||||
it("getInstructionsDir returns the managed bundle directory path", async () => {
|
||||
const agent = await store.createAgent({ name: "dir-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
expect(store.getInstructionsDir(agent.id)).toBe(join(testDir, "agents", `${agent.id}-instructions`));
|
||||
});
|
||||
|
||||
it("listBundleFiles returns empty for missing directory and sorted .md files only", async () => {
|
||||
const agent = await store.createAgent({ name: "list-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
expect(await store.listBundleFiles(agent.id)).toEqual([]);
|
||||
|
||||
@@ -61,6 +81,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
|
||||
it("readBundleFile reads content and rejects missing/traversal paths", async () => {
|
||||
const agent = await store.createAgent({ name: "read-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
await store.writeBundleFile(agent.id, "AGENTS.md", "Hello bundle");
|
||||
await expect(store.readBundleFile(agent.id, "AGENTS.md")).resolves.toBe("Hello bundle");
|
||||
@@ -71,6 +92,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
|
||||
it("writeBundleFile creates directories, overwrites, validates paths, and enforces max file count", async () => {
|
||||
const agent = await store.createAgent({ name: "write-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
const dir = store.getInstructionsDir(agent.id);
|
||||
|
||||
await store.writeBundleFile(agent.id, "AGENTS.md", "first");
|
||||
@@ -93,6 +115,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
|
||||
it("deleteBundleFile removes files and throws when missing", async () => {
|
||||
const agent = await store.createAgent({ name: "delete-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
const filePath = join(store.getInstructionsDir(agent.id), "AGENTS.md");
|
||||
|
||||
await store.writeBundleFile(agent.id, "AGENTS.md", "to-delete");
|
||||
@@ -104,6 +127,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
|
||||
it("setBundleConfig validates input and creates managed directory", async () => {
|
||||
const agent = await store.createAgent({ name: "config-agent", role: "executor" });
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const managed = await store.setBundleConfig(agent.id, {
|
||||
mode: "managed",
|
||||
@@ -143,6 +167,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
role: "executor",
|
||||
instructionsText: "Legacy text content",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const migrated = await store.migrateLegacyInstructions(agent.id);
|
||||
|
||||
@@ -166,6 +191,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
role: "executor",
|
||||
instructionsPath: sourcePath,
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const migrated = await store.migrateLegacyInstructions(agent.id);
|
||||
|
||||
@@ -189,6 +215,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
instructionsText: "Primary inline content",
|
||||
instructionsPath: sourcePath,
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const migrated = await store.migrateLegacyInstructions(agent.id);
|
||||
|
||||
@@ -215,6 +242,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
},
|
||||
instructionsText: "should-stay",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const migrated = await store.migrateLegacyInstructions(agent.id);
|
||||
|
||||
@@ -231,6 +259,7 @@ describe("AgentStore — instructions bundle", () => {
|
||||
name: "no-legacy",
|
||||
role: "executor",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const migrated = await store.migrateLegacyInstructions(agent.id);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { AgentStore } from "../agent-store.js";
|
||||
describe("AgentStore — instructions fields", () => {
|
||||
let testDir: string;
|
||||
let store: AgentStore;
|
||||
const createdAgentIds: string[] = [];
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = await mkdtemp(join(tmpdir(), "agent-instructions-test-"));
|
||||
@@ -15,7 +16,23 @@ describe("AgentStore — instructions fields", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(testDir, { recursive: true, force: true });
|
||||
// Teardown order: entity cleanup first, then filesystem
|
||||
// Delete all created agents explicitly
|
||||
for (const agentId of createdAgentIds) {
|
||||
try {
|
||||
await store.deleteAgent(agentId);
|
||||
} catch {
|
||||
// Ignore cleanup errors for already-removed entities
|
||||
}
|
||||
}
|
||||
createdAgentIds.length = 0;
|
||||
|
||||
// Filesystem cleanup last
|
||||
try {
|
||||
await rm(testDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
it("creates an agent with instructionsText", async () => {
|
||||
@@ -24,6 +41,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsText: "Always use TypeScript strict mode.",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
expect(agent.instructionsText).toBe("Always use TypeScript strict mode.");
|
||||
expect(agent.instructionsPath).toBeUndefined();
|
||||
@@ -35,6 +53,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsPath: ".fusion/agents/custom.md",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
expect(agent.instructionsPath).toBe(".fusion/agents/custom.md");
|
||||
expect(agent.instructionsText).toBeUndefined();
|
||||
@@ -47,6 +66,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
instructionsText: "Check for security issues.",
|
||||
instructionsPath: ".fusion/agents/reviewer.md",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
expect(agent.instructionsText).toBe("Check for security issues.");
|
||||
expect(agent.instructionsPath).toBe(".fusion/agents/reviewer.md");
|
||||
@@ -57,6 +77,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
name: "test-agent",
|
||||
role: "executor",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
expect(agent.instructionsText).toBeUndefined();
|
||||
expect(agent.instructionsPath).toBeUndefined();
|
||||
@@ -68,6 +89,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsText: "Always write tests.",
|
||||
});
|
||||
createdAgentIds.push(created.id);
|
||||
|
||||
const loaded = await store.getAgent(created.id);
|
||||
expect(loaded).not.toBeNull();
|
||||
@@ -80,6 +102,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsPath: ".fusion/agents/instructions.md",
|
||||
});
|
||||
createdAgentIds.push(created.id);
|
||||
|
||||
const loaded = await store.getAgent(created.id);
|
||||
expect(loaded).not.toBeNull();
|
||||
@@ -91,6 +114,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
name: "test-agent",
|
||||
role: "executor",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsText: "Use functional programming patterns.",
|
||||
@@ -104,6 +128,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
name: "test-agent",
|
||||
role: "executor",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsPath: ".fusion/agents/new-instructions.md",
|
||||
@@ -118,6 +143,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsText: "Some instructions",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsText: "",
|
||||
@@ -133,6 +159,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
role: "executor",
|
||||
instructionsPath: ".fusion/agents/old.md",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsPath: "",
|
||||
@@ -148,6 +175,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
instructionsText: "Old text",
|
||||
instructionsPath: "old.md",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsText: "New text",
|
||||
@@ -170,6 +198,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
title: "My Executor",
|
||||
instructionsText: "Initial",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const updated = await store.updateAgent(agent.id, {
|
||||
instructionsText: "Updated",
|
||||
@@ -188,6 +217,7 @@ describe("AgentStore — instructions fields", () => {
|
||||
instructionsText: "Cached instructions",
|
||||
instructionsPath: ".fusion/cached.md",
|
||||
});
|
||||
createdAgentIds.push(agent.id);
|
||||
|
||||
const cached = store.getCachedAgent(agent.id);
|
||||
expect(cached).not.toBeNull();
|
||||
|
||||
@@ -30,9 +30,30 @@ describe("CentralCore Integration", () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Cleanup
|
||||
await central.close();
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
// Teardown order: entity cleanup first, then infrastructure, then filesystem
|
||||
// Unregister all tracked projects first (not just a subset from assertions)
|
||||
for (const project of projects) {
|
||||
try {
|
||||
await central.unregisterProject(project.id);
|
||||
} catch {
|
||||
// Ignore cleanup errors for already-removed entities
|
||||
}
|
||||
}
|
||||
projects.length = 0;
|
||||
|
||||
// Close CentralCore before filesystem cleanup
|
||||
try {
|
||||
await central.close();
|
||||
} catch {
|
||||
// Ignore close errors
|
||||
}
|
||||
|
||||
// Filesystem cleanup last
|
||||
try {
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
it("should register multiple projects", async () => {
|
||||
|
||||
Reference in New Issue
Block a user