feat(FN-3580): restore canonical agent lifecycle and remove terminated agen
This merge restores the canonical agent lifecycle with termination scoped at the run level (FN-3580, 4 steps), adds sender-side wake recipient override for messages, and introduces test isolation CI enforcement with a stuck-requeue race fix. UI changes remove terminated-agent indicators from AgentDe Fusion-Task-Id: FN-3580
This commit is contained in:
@@ -16,11 +16,10 @@ vi.mock("@fusion/core", () => ({
|
||||
})),
|
||||
AGENT_VALID_TRANSITIONS: {
|
||||
idle: ["active"],
|
||||
active: ["running", "paused", "terminated"],
|
||||
running: ["active", "paused", "error", "terminated"],
|
||||
paused: ["active", "terminated"],
|
||||
error: ["active", "terminated"],
|
||||
terminated: ["idle", "active", "running"],
|
||||
active: ["running", "paused"],
|
||||
running: ["active", "paused", "error"],
|
||||
paused: ["active"],
|
||||
error: ["active"],
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -124,14 +123,6 @@ describe("runAgentStop", () => {
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("cannot transition to 'paused'"));
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("should reject stopping a terminated agent (invalid transition)", async () => {
|
||||
mockGetAgent.mockResolvedValue(makeAgent("terminated"));
|
||||
|
||||
await expect(runAgentStop("agent-test123")).rejects.toThrow("process.exit");
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("cannot transition to 'paused'"));
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("runAgentStart", () => {
|
||||
@@ -152,16 +143,6 @@ describe("runAgentStart", () => {
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("✓ Agent agent-test123 started"));
|
||||
});
|
||||
|
||||
it("should start a terminated agent", async () => {
|
||||
mockGetAgent.mockResolvedValue(makeAgent("terminated"));
|
||||
mockUpdateAgentState.mockResolvedValue(makeAgent("active"));
|
||||
|
||||
await runAgentStart("agent-test123");
|
||||
|
||||
expect(mockUpdateAgentState).toHaveBeenCalledWith("agent-test123", "active");
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("✓ Agent agent-test123 started"));
|
||||
});
|
||||
|
||||
it("should start an idle agent", async () => {
|
||||
mockGetAgent.mockResolvedValue(makeAgent("idle"));
|
||||
mockUpdateAgentState.mockResolvedValue(makeAgent("active"));
|
||||
|
||||
@@ -52,14 +52,12 @@ async function git(command: string, cwd: string): Promise<string> {
|
||||
describe("init command", () => {
|
||||
let tempProjectDir: string;
|
||||
let tempHomeDir: string;
|
||||
let originalHome: string | undefined;
|
||||
let originalUserProfile: string | undefined;
|
||||
const isolatedHome = process.env.HOME;
|
||||
const isolatedUserProfile = process.env.USERPROFILE;
|
||||
|
||||
beforeEach(() => {
|
||||
tempProjectDir = tempDir("fn-init-test-");
|
||||
tempHomeDir = tempDir("fn-init-home-");
|
||||
originalHome = process.env.HOME;
|
||||
originalUserProfile = process.env.USERPROFILE;
|
||||
process.env.HOME = tempHomeDir;
|
||||
process.env.USERPROFILE = tempHomeDir;
|
||||
mockCentralInit.mockResolvedValue(undefined);
|
||||
@@ -81,15 +79,15 @@ describe("init command", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalHome === undefined) {
|
||||
if (isolatedHome === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = originalHome;
|
||||
process.env.HOME = isolatedHome;
|
||||
}
|
||||
if (originalUserProfile === undefined) {
|
||||
if (isolatedUserProfile === undefined) {
|
||||
delete process.env.USERPROFILE;
|
||||
} else {
|
||||
process.env.USERPROFILE = originalUserProfile;
|
||||
process.env.USERPROFILE = isolatedUserProfile;
|
||||
}
|
||||
|
||||
if (existsSync(tempProjectDir)) {
|
||||
|
||||
@@ -2227,7 +2227,7 @@ export default function kbExtension(pi: ExtensionAPI) {
|
||||
promptGuidelines: [
|
||||
"Use to pause an agent that is currently running or active",
|
||||
"Stopped agents can be resumed with fn_agent_start",
|
||||
"Agents in 'idle', 'error', or 'terminated' state cannot be stopped",
|
||||
"Agents in 'idle', 'error', or already-paused state cannot be stopped",
|
||||
],
|
||||
parameters: Type.Object({
|
||||
id: Type.String({ description: "Agent ID to stop (e.g., agent-abc123)" }),
|
||||
|
||||
Reference in New Issue
Block a user